<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jax Gauthier</title>
    <description>The latest articles on DEV Community by Jax Gauthier (@just_insane).</description>
    <link>https://dev.to/just_insane</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F152566%2F1e93d9db-13c6-4756-aa60-d01185f0d2b3.png</url>
      <title>DEV Community: Jax Gauthier</title>
      <link>https://dev.to/just_insane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/just_insane"/>
    <language>en</language>
    <item>
      <title>Getting Started with Cloudflare Workers</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Tue, 11 Feb 2020 17:00:00 +0000</pubDate>
      <link>https://dev.to/just_insane/getting-started-with-cloudflare-workers-2cpn</link>
      <guid>https://dev.to/just_insane/getting-started-with-cloudflare-workers-2cpn</guid>
      <description>&lt;p&gt;I have recently had the need to redirect a few subdomains to another domain, due to old links still being used by public individuals.&lt;/p&gt;

&lt;p&gt;I wanted a solution that would not require running another web server, so I started looking into a few different options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudflare Page Rules
&lt;/h2&gt;

&lt;p&gt;While Page Rules do want I want, they were either not flexible enough (could only target a single subdomain), and would be relatively expensive for the number I would need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudflare Workers
&lt;/h2&gt;

&lt;p&gt;Cloudflare Workers are pretty cool. They allow you to run JS code at the Cloudflare edge. They are basically functions-as-a-service, which are super fast and customizable.&lt;/p&gt;

&lt;p&gt;I was able to set up a function in less than 5 minutes that allows me to redirect any subdomain to another domain.&lt;/p&gt;

&lt;p&gt;The function I am using looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function handleRequest(request) {
  return Response.redirect(someURLToRedirectTo, code)
}
addEventListener('fetch', async event =&amp;gt; {
  event.respondWith(handleRequest(event.request))
})
/**
 * Example Input
 * @param {Request} url where to redirect the response
 * @param {number?=301|302} type permanent or temporary redirect
 */
const someURLToRedirectTo = 'https://homelab.blog'
const code = 302 // Temporary Redirect

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, it handles requests by sending a 302 Temporary Redirect to my current blog page.&lt;/p&gt;

&lt;p&gt;Additionally, the function is super fast. It seems significantly faster than if I were to run a webserver to handle the redirect myself.&lt;/p&gt;

&lt;p&gt;It is also using the &lt;a href="https://developers.cloudflare.com/workers/about/routes/"&gt;routes&lt;/a&gt; function. You still have to define a DNS name for the URLs you want to redirect, and I currently just CNAME them to the workers.dev hostname of the worker.&lt;/p&gt;

&lt;p&gt;This is just a start of what workers/functions are able to do, and I am excited to see where else I can use them to make my life easier.&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Configuring Istio with OIDC authentication</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Tue, 04 Feb 2020 23:51:17 +0000</pubDate>
      <link>https://dev.to/just_insane/configuring-istio-with-oidc-authentication-4jpj</link>
      <guid>https://dev.to/just_insane/configuring-istio-with-oidc-authentication-4jpj</guid>
      <description>&lt;p&gt;In this blog post, we will look at the first part of my ideal setup, which is to secure inbound communication via an authenticating reverse proxy (OAuth2_Proxy), and Keycloak.&lt;/p&gt;

&lt;p&gt;This setup will use the follow technologies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Istio (ingress gateway)

&lt;ol&gt;
&lt;li&gt;Certmanager (certificates) - not covered in this post&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;OAuth2_Proxy (controls the OIDC flow)

&lt;ol&gt;
&lt;li&gt;Redis (session storage)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Keycloak (OIDC Provider)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Istio
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://istio.io/"&gt;Istio&lt;/a&gt; is a service mesh that allows you to define and secure services in your Kubernetes cluster. In my lab, I use it as the ingress gateway for my cluster, and I am planning on using it to secure service-to-service communication using mutual-tls.&lt;/p&gt;

&lt;p&gt;Istio will require a valid certificate for the gateway, you can either set this up via cert-manager, or by importing a certificate into your cluster manually.&lt;/p&gt;

&lt;p&gt;Here are some example config files for setting up basic services in Istio:&lt;/p&gt;

&lt;p&gt;Istio Gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1alpha3&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gateway&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gateway&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;istio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingressgateway&lt;/span&gt;
  &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTP&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;httpsRedirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPS&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;credentialName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changeme&lt;/span&gt;
      &lt;span class="na"&gt;httpsRedirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SIMPLE&lt;/span&gt;
      &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sds&lt;/span&gt;
      &lt;span class="na"&gt;serverCertificate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Destination Rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1alpha3&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DestinationRule&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth-corp-justin-tech-com&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth.corp.justin-tech.com&lt;/span&gt;
  &lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;loadBalancer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;simple&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ROUND_ROBIN&lt;/span&gt;
    &lt;span class="na"&gt;portLevelSettings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
      &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SIMPLE&lt;/span&gt;
        &lt;span class="na"&gt;sni&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth.corp.justin-tech.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Virtual Service:&lt;/p&gt;

&lt;p&gt;oauthproxy-service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1alpha3&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VirtualService&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauthproxy-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gateways&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gateway.istio-system&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oauth.corp.justin-tech.com&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oauth.justin-tech.com&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauthproxy-service&lt;/span&gt;
        &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4180&lt;/span&gt;
      &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the virtual service for your application, I am using Rancher-Demo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1alpha3&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VirtualService&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rancher-demo&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gateways&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gateway.istio-system&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rancher-demo.corp.justin-tech.com&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rancher-demo&lt;/span&gt;
        &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Envoy Filter, which is the part that starts the redirection for unauthenticated users. This is similar to the auth-url function of Nginx-Ingress. This acts on your Ingress-Gateway workload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1alpha3&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EnvoyFilter&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authn-filter&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workloadLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;istio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingressgateway&lt;/span&gt;
  &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;filterConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;http_service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;server_uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://oauthproxy-service.default.svc.cluster.local&lt;/span&gt;
          &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;outbound|4180||oauthproxy-service.default.svc.cluster.local&lt;/span&gt;
          &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.5s&lt;/span&gt;
        &lt;span class="na"&gt;authorizationRequest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;allowedHeaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cookie"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded-access-token"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded-user"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded-email"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded-proto"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxy-authorization"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-agent"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded-host"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded-for"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-auth-request"&lt;/span&gt;
        &lt;span class="na"&gt;authorizationResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;allowedClientHeaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxy-authenticate"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set-cookie"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;www-authenticate"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-auth-request"&lt;/span&gt;
          &lt;span class="na"&gt;allowedUpstreamHeaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxy-authenticate"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set-cookie"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;www-authenticate"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-forwarded"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-auth-request"&lt;/span&gt;
    &lt;span class="na"&gt;filterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;envoy.ext_authz&lt;/span&gt;
    &lt;span class="na"&gt;filterType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTP&lt;/span&gt;
    &lt;span class="na"&gt;listenerMatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;portNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
      &lt;span class="na"&gt;listenerType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GATEWAY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important parts are to set the server_uri. The allowed lists of headers is probably more than what is needed, but it works for me.&lt;/p&gt;

&lt;p&gt;This final part is optional, if you omit this part, you would be able to use the standard OAuth2_Proxy setup which is to send the cookies to the client directly, instead of using Redis as a session store. This configuration uses Istio's JWT authentication validation to ensure that every request to your service is authenticated by your issuer. You could expand on this by requiring specific groups per service, and by doing client certificate validation (which you could also couple with Keycloak's client certificate validation), for the best authentication of incoming requests.&lt;/p&gt;

&lt;p&gt;This is set per service with the target definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authentication.istio.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Policy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingress-auth-policy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rancher-demo&lt;/span&gt;
  &lt;span class="na"&gt;origins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;jwt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://auth.justin-tech.com/auth/realms/Justin-Tech"&lt;/span&gt;
      &lt;span class="na"&gt;jwksUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://auth.justin-tech.com/auth/realms/Justin-Tech/protocol/openid-connect/certs"&lt;/span&gt;
  &lt;span class="na"&gt;principalBinding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;USE_ORIGIN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Oauth2_Proxy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pusher.github.io/oauth2_proxy"&gt;OAuth2_Proxy&lt;/a&gt; performs the OIDC flow for unauthenticated users. We will need to use the Redis session store, as having the ID Token sent to the browser results in cookies that are too long, and splitting the cookie into parts does not work with Istio (see &lt;a href="https://pusher.github.io/oauth2_proxy/configuration#configuring-for-use-with-the-nginx-auth_request-directive"&gt;https://pusher.github.io/oauth2_proxy/configuration#configuring-for-use-with-the-nginx-auth_request-directive&lt;/a&gt; for an example that spits the cookies with Nginx Ingress support).&lt;/p&gt;

&lt;p&gt;Oauth2_Proxy Deployment example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--provider=oidc&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--provider-display-name="Keycloak"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--email-domain=corp.justin-tech.com&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--email-domain=justin-tech.com&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--pass-access-token=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--pass-authorization-header=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--set-authorization-header=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--oidc-issuer-url=https://auth.justin-tech.com/auth/realms/Justin-Tech&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--login-url=https://auth.justin-tech.com/auth/realms/Justin-Tech/protocol/openid-connect/auth&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--redeem-url=https://auth.justin-tech.com/auth/realms/Justin-Tech/protocol/openid-connect/token&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--validate-url=https://auth.justin-tech.com/auth/realms/Justin-Tech/protocol/openid-connect/userinfo&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--http-address=0.0.0.0:4180&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--cookie-expire=4h0m0s&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--whitelist-domain=".corp.justin-tech.com"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--cookie-domain=.justin-tech.com&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--standard-logging=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--auth-logging=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--request-logging=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--skip-provider-button=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--upstream=static://&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--redis-connection-url=redis://redis-master.default.svc.cluster.local:6379&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--session-store-type=redis&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OAUTH2_PROXY_CLIENT_ID&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rancher-demo&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OAUTH2_PROXY_CLIENT_SECRET&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# docker run -ti --rm python:3-alpine python -c 'import secrets,base64; print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))));'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OAUTH2_PROXY_COOKIE_SECRET&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OAUTH2_PROXY_COOKIE_DOMAIN&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.justin-tech.com&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;quay.io/pusher/oauth2_proxy:v4.1.0&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4180&lt;/span&gt;
              &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauthproxy-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4180&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4180&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above config is what I am using to deploy OAuth2_Proxy, some of the configuration is probably unnecessary. Some important parts are the URLs for your OIDC Provider (Keycloak in my case), and the cookie domain, if you have a domain and subdomains that are being used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redis
&lt;/h3&gt;

&lt;p&gt;I am using the stable/redis helm chart, with minimal configuration explained below. Redis is needed in order to pass JWT tokens from Keycloak to Istio, otherwise the cookies are too large and get split (which is not supported easily in Istio). The downside is that currently OAuth2_Proxy does not support a password on the Redis connection.&lt;/p&gt;

&lt;p&gt;The standard values.yaml from redis is fine to use, though you can change a few options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable persistence for the Redis master and slaves&lt;/li&gt;
&lt;li&gt;Enable metrics (if you want)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Keycloak
&lt;/h2&gt;

&lt;p&gt;i will not cover Keycloak too much in this post, as I have other posts available which cover setting up Keycloak. One thing to note is that you need to set the Redirect URL to either a wildcard, or by setting up one OAuth2_Proxy service per service, or have your services available at different URIs instead of subdomains. This could be a security issue as any redirect url could be set, please consider this before implementing.&lt;/p&gt;

&lt;p&gt;Altogether, this setup allows you to use Istio as your ingress-gateway, which provides a lot of features if you are using the rest of their service mesh, including mutual TLS inside the cluster, and integration with Kiali, for example. It allows you to use a service for starting/handling the OIDC flow (if you are using third party applications, or just want an authenticating proxy in front of your applications), and allows you to use any OIDC provider to do it.&lt;/p&gt;

</description>
      <category>homelab</category>
      <category>istio</category>
    </item>
    <item>
      <title>Getting Started with Kubernetes (at home) — Part 3</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Sat, 04 May 2019 16:00:00 +0000</pubDate>
      <link>https://dev.to/just_insane/getting-started-with-kubernetes-at-home-part-3-1bcc</link>
      <guid>https://dev.to/just_insane/getting-started-with-kubernetes-at-home-part-3-1bcc</guid>
      <description>&lt;p&gt;In the first two parts of this series, we looked at setting up a production Kubernetes cluster in our labs. In part three of this series, we are going to deploy some services to our cluster such as &lt;a href="https://guacamole.apache.org/"&gt;Guacamole&lt;/a&gt; and &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Step-by-step documentation and further service examples are &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/docs/services/services.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guacamole
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://guacamole.apache.org/"&gt;Guacamole&lt;/a&gt; is a very useful piece of software that allows you to remotely connect to your devices via RDP, SSH, or other protocols. I use it extensively to access my lab resources, even when I am at home.&lt;/p&gt;

&lt;p&gt;You can use this &lt;a href="https://github.com/Just-Insane/apache-guacamole-helm-chart"&gt;Helm Chart&lt;/a&gt; to install Guacamole on your Kubernetes cluster. The steps are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Guacamole Helm Chart from &lt;a href="https://github.com/Just-Insane/apache-guacamole-helm-chart"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Apply any changes to &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/services/guacamole/values.yaml"&gt;values.yaml&lt;/a&gt; such as the annotations and ingress settings.&lt;/li&gt;
&lt;li&gt;Deploy the Helm Chart from the &lt;code&gt;apache-guacamole-helm-chart&lt;/code&gt; directory 

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helm install . -f values.yaml --name=guacamole --namespace=guacamole&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An ingress is automatically created by the Helm Chart, and you can access it based on the &lt;code&gt;hosts:&lt;/code&gt; section of &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/services/guacamole/values.yaml"&gt;values.yaml&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you have deployed the Helm Chart, you should be able to access Guacamole at the ingress hostname specified in values.yaml.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keycloak
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; is an open-source single sign-on solution that is similar to Microsoft’s ADFS product. You can read more about Keycloak on my &lt;a href="https://homelab.blog/blog/security/keycloak-part-1-what-is-sso/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is a stable Keycloak Helm Chart available in the default Helm repo, which we will be using to deploy Keycloak, you can find it &lt;a href="https://github.com/helm/charts/tree/master/stable/keycloak"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Apply any changes to &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/services/keycloak/values.yaml"&gt;values.yaml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Deploy the helm chart stable/keycloak with values 

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helm install --name keycloak stable/keycloak --values values.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create an &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/services/keycloak/ingress.yaml"&gt;ingress&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl apply -f ingress.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Get the default password for the &lt;code&gt;keycloak&lt;/code&gt; user. 

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl get secret --namespace default keycloak-http -o jsonpath="{.data.password}" | base64 --decode; echo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Though this article is on the shorter side, hopefully it exemplifies how easy it can be to run services in Kubernetes. We mainly looked at pre-made Helm Charts in this article, however deploying a service without a Chart can also be just as easy. I prefer using charts as I find it easier to manage than straight Kubernetes manifest files.&lt;/p&gt;

&lt;p&gt;You can checkout my public Kubernetes repo at &lt;a href="https://gitlab.com/just.insane/kubernetes/"&gt;https://gitlab.com/just.insane/kubernetes/&lt;/a&gt; for further information and more service examples.&lt;/p&gt;

</description>
      <category>homelab</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Getting Started with Kubernetes (at home) — Part 2</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Sat, 27 Apr 2019 20:20:02 +0000</pubDate>
      <link>https://dev.to/just_insane/getting-started-with-kubernetes-at-home-part-2-3clc</link>
      <guid>https://dev.to/just_insane/getting-started-with-kubernetes-at-home-part-2-3clc</guid>
      <description>&lt;p&gt;In the first part of the series, we looked at installing a bare bones Kubernetes cluster in some CentOS 7 VMs. In this part, we are going to look at setting up some back-end services, like a load balancer and ingress.&lt;/p&gt;

&lt;p&gt;Some important things needed to properly run a Kubernetes cluster are a &lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/"&gt;storage class&lt;/a&gt; or manual storage configuration via &lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/"&gt;volumes&lt;/a&gt;, a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer"&gt;load balancer&lt;/a&gt; though not strictly needed makes accessing services much easier, and an &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/"&gt;ingress&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/docs/configuration/configuration.md"&gt;Step-by-step documentation is here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting up Helm
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://helm.sh"&gt;Helm&lt;/a&gt; is known as the “package manager for Kubernetes”, it is a tool that is used to template Kubernetes manifest files in a way that makes it easy to install new applications. I use Helm for all my service installation on Kubernetes due to it’s ease, and simplicity when getting started.&lt;/p&gt;

&lt;p&gt;If you did not enable the optional Helm installation via Kubespray, we should do that first.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Download Helm
&lt;/h4&gt;

&lt;p&gt;If you are on a Mac, you can install Helm via brew install kubernetes-helm. The Helm documentation has instructions for other methods of installation (unpacking a .zip and adding it to the $PATH).&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Setup a Tiller user with RBAC
&lt;/h4&gt;

&lt;p&gt;You can use this &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/rbac-config.yaml"&gt;rbac-config.yaml&lt;/a&gt; file to setup the user, download it and run the following commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl create -f rbac-config.yaml&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Initialize Helm
&lt;/h4&gt;

&lt;p&gt;Now we have to initialize Helm by deploying Tiller. The simplest method is to run &lt;code&gt;helm init --service-account tiller&lt;/code&gt;. We have to specify the service account for tiller to use due to RBAC.&lt;/p&gt;

&lt;h4&gt;
  
  
  Persistent Storage
&lt;/h4&gt;

&lt;p&gt;Since Docker, and by extension Kubernetes requires storage for any persistent data, it is important to provide Kubernetes some storage. If you were using a cloud provider, this would be handled for you, and you would use the providers default storage solution. In our case, we need to tell Kubernetes what storage to use.&lt;/p&gt;

&lt;p&gt;We are going to use NFS storage for our cluster, which requires you to have an existing NFS server.&lt;/p&gt;

&lt;p&gt;Once we have an NFS server, we are going to use the &lt;code&gt;nfs-client-provisioner&lt;/code&gt;, which is available via Helm, to access that storage via Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/"&gt;storage class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Simply run &lt;code&gt;helm install stable/nfs-client-provisioner -name nfs-client -namespace kube-system -set nfs.server=10.0.40.5 -set nfs.path=/mnt/Shared/kubernetes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s break that down a bit, the above command does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tell Helm to install the Helm Chart &lt;code&gt;stable/nfs-client-provisioner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Give the release a name &lt;code&gt;nfs-client&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;nfs-client&lt;/code&gt; to the &lt;code&gt;kube-system&lt;/code&gt; namespace&lt;/li&gt;
&lt;li&gt;Set the NFS Server IP to 10.0.40.5 you should change this as necessary&lt;/li&gt;
&lt;li&gt;Set the NFS Path to /mnt/Shared/kubernetes you should change this to the share path on your NFS server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We should now check the status of nfs-client to ensure it is running correctly, via helm status nfs-client which should show ready.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install MetalLB
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://metallb.universe.tf/"&gt;MetalLB&lt;/a&gt; is a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer"&gt;load balancer&lt;/a&gt; for Kubernetes that allows Kubernetes services to retrieve IP addresses when needed that are on the LAN or WAN. This greatly simplifies network access to services in a bare-metal (or VM) based Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;MetalLB has some requirements that we must comply with, namely, we have to have a Kubernetes cluster, a supported cluster network configuration, some IPv4 addresses, and optionally hardware that supports BGP. The first two are automatically handled by Kubespray in section 1, and for the IP addresses, you can provide a block that is outside your DHCP server’s scope on the same network as the Kubernetes nodes. I have not used the BGP option, as I do not have BGP hardware available.&lt;/p&gt;

&lt;p&gt;You can install MetalLB via Helm with the following command &lt;code&gt;helm install -name metallb -f values.yaml stable/metallb&lt;/code&gt; an example values.yaml file can be found &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/metallb/values.yaml"&gt;here&lt;/a&gt;. Notice the &lt;code&gt;configInline&lt;/code&gt; section that defines the IP addresses MetalLB will hand out.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install Nginx-Ingress
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/kubernetes/ingress-nginx"&gt;Nginx-Ingress&lt;/a&gt; is an &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/"&gt;Ingress&lt;/a&gt; service for Kubernetes. Ingresses serve to manage external access to services in the cluster. It is important to understand how nginx-ingress works, so I recommend you read through the &lt;a href="https://github.com/helm/charts/tree/master/stable/nginx-ingress"&gt;GitHub documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have done that, we can install Nginx-Ingress via Helm. You can review the &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/nginx-ingress/values.yaml"&gt;values.yaml&lt;/a&gt;as an example, the main thing to change being the &lt;code&gt;default-ssl-certificate&lt;/code&gt; that Nginx should use.&lt;/p&gt;

&lt;p&gt;Once you have done that, you can install it via &lt;code&gt;helm install -name nginx-ingress -f values.yaml stable/nginx-ingress -namespace nginx-ingress&lt;/code&gt; which does the following.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tell Helm to install the Helm Chart &lt;code&gt;stable/nginx-ingress&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;With the release name &lt;code&gt;nginx-ingress&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To the &lt;code&gt;nginx-ingress&lt;/code&gt; namespace&lt;/li&gt;
&lt;li&gt;With the values from &lt;code&gt;values.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since the type is set to loadBalancer, MetalLB will automatically provide an external IP to the service from the provided IP addresses, which you can point your DNS or Port Forwards to in order to access your cluster’s services.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install Cert-Manager
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://docs.cert-manager.io/en/latest/"&gt;Cert-Manager&lt;/a&gt; is a complex service that allows us to automatically retrieve and renew SSL certificates from certificate providers. It works with Nginx-Ingress to ensure that all of our services are available via a secured connection over HTTPS.&lt;/p&gt;

&lt;p&gt;There are a number of steps required to setup Cert-Manager correctly. You should start by reviewing the Helm Chart documentation &lt;a href="https://github.com/jetstack/cert-manager/tree/master/deploy/charts/cert-manager"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prerequisites&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the CustomResourceDefinition resources separately&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl apply -f [https://raw.githubusercontent.com/jetstack/cert-manager/release-0.7/deploy/manifests/00-crds.yaml](https://raw.githubusercontent.com/jetstack/cert-manager/release-0.7/deploy/manifests/00-crds.yaml)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Create the namespace for cert-manager&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl create namespace cert-manager&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Label the cert-manager namespace to disable resource validation&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Add the Jetstack Helm repository&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helm repo add jetstack [https://charts.jetstack.io](https://charts.jetstack.io)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Update your local Helm chart repository cache&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helm repo update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Installation via Helm&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make any changes to &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/cert-manager/values.yaml"&gt;values.yaml&lt;/a&gt; notably the &lt;code&gt;podDnsConfig/nameservers&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deploy the Helm Chart&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helm install -name cert-manager -namespace cert-manager -f values.yaml jetstack/cert-manager&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Verify the Installation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is covered in the official documentation which you can find &lt;a href="https://docs.cert-manager.io/en/latest/getting-started/install.html#verifying-the-installation"&gt;here&lt;/a&gt;. It has you create a test issuer and get a self-signed certificate to ensure everything is working properly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Create the Production Issuer&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Creation of a test issuer is omitted for brevity, but please ensure you try creating a test issuer first so you do not hit the Let’s Encrypt rate limits.&lt;/p&gt;

&lt;p&gt;If you are using Let’s Encrypt and Cloudflare, you can use this &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/cert-manager/letsencrypt.yaml"&gt;letsencrypt.yaml&lt;/a&gt; file. Remember to change the values as needed, especially anything marked with changeme.&lt;/p&gt;

&lt;p&gt;Once you are ready, run &lt;code&gt;kubectl apply -f letsencrypt.yaml&lt;/code&gt; to create the issuer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Create Cloudflare API Key Secret&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we need to add our Cloudflare API key into a Kubernetes secret. You can use &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/cert-manager/cloudflare-secret.yaml"&gt;cloudflare-secret.yaml&lt;/a&gt; as an example.&lt;/p&gt;

&lt;p&gt;Once you have made your changes, create the secret with &lt;code&gt;kubectl apply -f cloudflare-secret.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Create the Default Certificate&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can now create the default certificate that Nginx-Ingress will use for serving our sites. See &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/cert-manager/certificate.yaml"&gt;certificate.yaml&lt;/a&gt; for an example.&lt;/p&gt;

&lt;p&gt;Once you have made your changes to the file, with regard to the names and domains, you can create the certificate with &lt;code&gt;kubectl apply -f certificate.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create an Ingress
&lt;/h4&gt;

&lt;p&gt;Now we can create an ingress for the Kubernetes dashboard, so instead of going to &lt;a href="https://masternode:6443/proxy/"&gt;https://masternode:6443/proxy/&lt;/a&gt; ect, we can go directly to &lt;a href="https://kubernetes.domain.com"&gt;https://kubernetes.domain.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first step is to create the dashboard ingress, which we can do with &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/configuration/dashboard/ingress.yaml"&gt;ingress.yaml&lt;/a&gt; once you have made your changes, you can create the ingress with &lt;code&gt;kubectl apply -f ingress.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can now go to &lt;a href="https://kubernetes.domain.com"&gt;https://kubernetes.domain.com&lt;/a&gt; to access your Kubernetes dashboard, after you add the domain to DNS via the nginx-ingress external IP.&lt;/p&gt;

&lt;p&gt;You now have a completely setup Kubernetes cluster running at home that you can test your services on, or use as a homelab.&lt;/p&gt;

</description>
      <category>homelab</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Getting Started with Kubernetes (at home) — Part 1</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Sat, 27 Apr 2019 03:44:18 +0000</pubDate>
      <link>https://dev.to/just_insane/getting-started-with-kubernetes-at-home-part-1-1lal</link>
      <guid>https://dev.to/just_insane/getting-started-with-kubernetes-at-home-part-1-1lal</guid>
      <description>&lt;p&gt;When you think about Kubernetes, you probably think AWS or GCP, a nice managed service where you can easily spin up resources and build applications on top of them. This is great, and honestly the best way to experience Kubernetes. However, if all you need is a lab to mess around in and experiment, or learn new things in, this can be very cost inefficient. That is why we are going to look at setting up Kubernetes ourselves.&lt;/p&gt;

&lt;p&gt;In this post, we are going to look at the initial deployment of Kubernetes, from creating our nodes (in this case CentOS 7 VMs) to getting a cluster up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Installing our VMs
&lt;/h2&gt;

&lt;p&gt;The first step is to create some VMs. I use a custom vCenter template in my lab, but if you do not have one of those, you can follow these simple steps.&lt;/p&gt;

&lt;p&gt;You will need to complete these steps on at least 1 machine, however more is certainly better to get the full benefit of Kubernetes.&lt;/p&gt;

&lt;p&gt;Your machine/VM should have at least 1 core and 3Gb of RAM.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install CentOS 7 from the USB ISO image, a basic install is fine&lt;/li&gt;
&lt;li&gt;Create a user for Ansible access. This user should be part of the sudo users group, and ideally have passwordless SSH authentication&lt;/li&gt;
&lt;li&gt;Assign static IP Addresses to your hosts. Optionally set a hostname.&lt;/li&gt;
&lt;li&gt;I hate to say it, but the official docs say to disable the firewall between the nodes, and I was unable to find documentation on which ports are needed.&lt;/li&gt;
&lt;li&gt;Optionally, add your hosts to DNS.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 2: Kubernetes Installation
&lt;/h2&gt;

&lt;p&gt;We are going to be using &lt;a href="https://github.com/kubernetes-sigs/kubespray"&gt;Kubespray&lt;/a&gt; for our cluster, as it makes creating and updating a Kubernetes cluster very simple and straightforward.&lt;/p&gt;

&lt;p&gt;You can find the official docs &lt;a href="https://github.com/kubernetes-sigs/kubespray/blob/master/docs/getting-started.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The quick guide is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the dependencies&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo pip install -r requirements.txt&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the example Inventory&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cp -rfp inventory/sample inventory/mycluster&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build the inventory, you can use the built in builder, or take a look &lt;a href="https://gitlab.com/just.insane/kubernetes/blob/master/src/installation/hosts.ini"&gt;here&lt;/a&gt; for an example. It is fine to have a single master, but the &lt;code&gt;kube-master&lt;/code&gt; and &lt;code&gt;etcd&lt;/code&gt; sections should be the same.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the cluster&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ansible-playbook -i inventory/mycluster/hosts.yml --become --become-user=root cluster.yml&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then all you have to do is wait while Kubespray deploys your cluster automatically. On my 6 node cluster, it usually takes about 10–15 minutes for the cluster to be completely setup and running.&lt;/p&gt;

&lt;p&gt;Note that in the Kubespray inventory there are a couple of options which are useful to enable. First, in the &lt;code&gt;addons.yaml&lt;/code&gt; file, it is a good idea to enable Helm and the Kubernetes Dashboard automatic deployments. It may also be beneficial to enable &lt;code&gt;kube_basic_auth&lt;/code&gt; in the &lt;code&gt;k8s-cluster.yaml&lt;/code&gt; file, if you are having issues with the default token based authentication. If you decide to do this later, you can simply make the change and then re-run the deployment with the command in step 4 above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Testing the Cluster
&lt;/h2&gt;

&lt;p&gt;You can test that your cluster is up and running with the following commands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;kubectl cluster-info&lt;/code&gt; which should return something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Kubernetes master is running at https://10.0.40.245:6444&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;kubectl get nodes&lt;/code&gt; which displays the state of all of your nodes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find more information about how I have setup Kubernetes at my &lt;a href="https://gitlab.com/just.insane/kubernetes"&gt;Gitlab repo&lt;/a&gt;, which has helpful code snippets, full configuration files, as well as expanded documentation.&lt;/p&gt;

</description>
      <category>homelab</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>What is Helm-Vault?</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Thu, 25 Apr 2019 16:01:00 +0000</pubDate>
      <link>https://dev.to/just_insane/what-is-helm-vault-55bg</link>
      <guid>https://dev.to/just_insane/what-is-helm-vault-55bg</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/Just-Insane/Helm-Vault"&gt;Helm-Vault&lt;/a&gt; is a new application designed to protect secrets contained in Helm Chart’s values.yaml files.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Problem:
&lt;/h4&gt;

&lt;p&gt;The problem with using Helm with Kubernetes is that there is no good way to secure your private configuration items stored in the YAML configuration files.&lt;/p&gt;

&lt;p&gt;There are multiple reasons you may want to do this, such as to audit who is accessing what secrets, or to prevent unauthorized modifications to the environment. Another reason may be that you want to have publicly available documentation without worrying about scrubbing the files.&lt;/p&gt;

&lt;h4&gt;
  
  
  Current Solutions:
&lt;/h4&gt;

&lt;p&gt;Currently available solutions require you to significantly modify the Helm Chart, or encrypt the entire document with GPG or a hosted KMS solution.&lt;/p&gt;

&lt;p&gt;This can be a pain to manage, who wants to use GPG all the time to work with files? What happens if the key is lost? What happens if the internet is down and you can’t access your KMS provider?&lt;/p&gt;

&lt;h4&gt;
  
  
  What makes Helm-Vault different:
&lt;/h4&gt;

&lt;p&gt;With Helm-Vault, you get full access to the structure and content of the YAML documents, even when they are in an “encrypted” state, this provides you a lot more flexibility. When publishing charts, you can seamlessly provide your encrypted YAML files, and with the deliminator, provide easily notable locations where information needs to be changed.&lt;/p&gt;

&lt;p&gt;If you run Hashicorp &lt;a href="https://www.vaultproject.io/"&gt;Vault&lt;/a&gt; internally, you will always have access to your secret data, and don’t have to worry about working with GPG keys, which makes life a lot easier for your developers.&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting Started:
&lt;/h4&gt;

&lt;p&gt;As long as you have Python 3.7, a working Hashicorp Vault environment, and a Vault token, you can get started with Helm-Vault in 2 easy steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pip3 install git+https://github.com/Just-Insane/helm-vault&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm plugin install https://github.com/Just-Insane/helm-vault&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find information about using Helm-Vault in the &lt;a href="https://github.com/Just-Insane/helm-vault/blob/master/README.md#usage-and-examples"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions or concerns, feel free to open an issue on the project’s &lt;a href="https://github.com/Just-Insane/helm-vault/issues"&gt;GitHub Issue Tracker&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>vault</category>
      <category>security</category>
    </item>
    <item>
      <title>The Importance of Security Testing</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Wed, 24 Apr 2019 23:08:28 +0000</pubDate>
      <link>https://dev.to/just_insane/the-importance-of-security-testing-ak6</link>
      <guid>https://dev.to/just_insane/the-importance-of-security-testing-ak6</guid>
      <description>&lt;p&gt;While setting up a new Keycloak client in my lab over the weekend, I discovered something odd, a number of users in my Keycloak database who should not have been there.&lt;/p&gt;

&lt;h4&gt;
  
  
  Background:
&lt;/h4&gt;

&lt;p&gt;In my homelab environment, I have been using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; for securing my services, either directly for applications like Nextcloud, Confluence, and Jira, or indirectly, via a authenticated reverse proxy, for things that don’t such as single page applications like Hashicorp’s &lt;a href="https://www.consul.io/"&gt;Consul&lt;/a&gt; or &lt;a href="https://jupyter.org/"&gt;Jupyter&lt;/a&gt;. This has been a fine setup, and has allowed me to access my internal applications easily and securely from anywhere, with 2FA and seamless access when moving between services. Or so I thought.&lt;/p&gt;

&lt;h4&gt;
  
  
  Discovery:
&lt;/h4&gt;

&lt;p&gt;After noticing some odd users in my Keycloak user’s list, I decided to do some digging. I knew I had initially allowed sign-ups to Keycloak to very locked down services, like read only access to parts of Confluence, and my internal issue tracker on Jira. These users were put into a default role in Keycloak called External-Users, which had very limited access to services on my network.&lt;/p&gt;

&lt;p&gt;I decided to create a new user and see what all could be accessed, for the hell of it. I opened a new private window so that I could ensure I was not using cookies from my authenticated session, and went to work creating a new user. I was happily greeted with a &lt;a href="https://duo.com/"&gt;Duo&lt;/a&gt; page (Duo is a 2FA provider that you can integrate with to protect many different services), until I realized there was an option to enroll myself as a user in Duo. That is when I realized there was an issue.&lt;/p&gt;

&lt;h4&gt;
  
  
  Breach:
&lt;/h4&gt;

&lt;p&gt;After registering myself as a new user in Duo, I started to poke around, going first to Confluence and Jira, and seeing that I still had my limited permissions, was a bit relived. Then I went to Consul, and the page opened right to the main app, showing all my services humming away happily. Next I went to Jupyter, and immediately was greeted with the option of creating a new shell session.&lt;/p&gt;

&lt;h4&gt;
  
  
  Containment:
&lt;/h4&gt;

&lt;p&gt;As soon as I was able to get access to Jupyter, I disabled signups on Keycloak, cleaned out the unknown users (some of which used legitimate emails), and set Duo to not allow users to enroll themselves. I also ensured there were no active sessions in Keycloak and started locking my network down to ensure there was nobody still inside the perimeter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Root Cause:
&lt;/h4&gt;

&lt;p&gt;The root cause of this issue was my reverse proxy. Knowing that most of my applications were secured behind it, especially the ones which do not handle their own authentication, I tore it apart. I didn’t have to look far to see the error in my ways.&lt;/p&gt;

&lt;p&gt;Almost all of my proxied services had this block in the server section (private information omitted):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;access_by_lua '
 local opts = {
 discovery = "$URL/.well-known/openid-configuration",
 redirect_uri_path = "/redirect_uri",
 redirect_uri_scheme = "https",
 client_id = "OpenResty",
 ssl_verify = "no",
 client_secret = "$ClientSecret",
 session_contents = {id_token=true}
 }
 local res, err = require("resty.openidc").authenticate(opts)

if err then
 ngx.status = 403
 ngx.say(err)
 ngx.exit(ngx.HTTP_FORBIDDEN)
 end
';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break that down a bit, shall we?&lt;/p&gt;

&lt;p&gt;My reverse proxy is OpenResty, a modified Nginx server setup to run Lua. On CentOS7 you have to build Nginx from source to add an OIDC authentication plugin, with OpenResty, it is built in.&lt;/p&gt;

&lt;p&gt;First, we define some options for the OIDC authentication:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The URL of the openid configuration information&lt;/li&gt;
&lt;li&gt;The path to redirect to, this is a URI that does not exist in the backend application that should be redirected to after authentication with Keycloak so the proxy can check the authentication&lt;/li&gt;
&lt;li&gt;The redirect scheme&lt;/li&gt;
&lt;li&gt;The Keycloak Client ID&lt;/li&gt;
&lt;li&gt;If SSL for Keycloak should be verified (this should be set to yes)&lt;/li&gt;
&lt;li&gt;The client secret that you get from Keycloak&lt;/li&gt;
&lt;li&gt;The session contents, in this case, we are just looking for the id_token&lt;/li&gt;
&lt;li&gt;The authentication check, more on this below&lt;/li&gt;
&lt;li&gt;What to do if there is an error, in this case, send a 403, print the error, and set HTTP_FORBIDDEN, then exit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Looking at the authentication check, do you see the problem? It is only checking that the person accessing the protected resource is authenticated to Keycloak. It does not check for their group, roles, or even to ensure they have a valid email address for the domain.&lt;/p&gt;

&lt;p&gt;Since anyone could sign up to Keycloak, and anyone could enroll themselves in Duo, they would be authenticated, and would therefore pass this check automatically, giving anyone who tried access to these internal applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  It Gets Worse:
&lt;/h4&gt;

&lt;p&gt;Knowing that I had setup external Identity Providers in Keycloak, such as Facebook and Google (adding external Identity Providers in Keycloak lets people sign in with other services which handle their own authentication), I went back and tested these out.&lt;/p&gt;

&lt;p&gt;I closed out my current private window, and opened a new one, going back to my Consul URL, and clicking on the login button for Google. When prompted, I entered a spare email address and password, and once I got through the Google verification, I was redirected back to Keycloak, and then to the main Consul page.&lt;/p&gt;

&lt;p&gt;After checking in Keycloak, I didn’t see a new user created with this email. Since authentication was handled by Google, all Keycloak was caring about was if the user successfully authenticated with Google, and just passed the user back to the proxy as being authenticated in Keycloak.&lt;/p&gt;

&lt;p&gt;Not only could anyone sign up for an account in Keycloak and add themselves to 2FA, they could completely bypass these steps without raising suspicion and not creating any user records.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lessons Learned:
&lt;/h4&gt;

&lt;p&gt;The lessons I learned through this were many, the first is to always double check everything, especially when it is security related. If I had checked these authentication flows when initially setting everything up, I would have caught these issues much sooner and this would not have been a problem.&lt;/p&gt;

&lt;p&gt;Second, it is important to understand and read the documentation fully. This could have been easily mitigated or completely prevented by adding more checks to OpenResty, disabling sign up or third party authentication in Keycloak, or preventing user self-enrollment in Duo.&lt;/p&gt;

&lt;p&gt;Third, check everything. If you enable a feature, ensure it does exactly what you are expecting it to do. If not, it is best to disable it, or get clarification as to why it is doing what it is.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion:
&lt;/h4&gt;

&lt;p&gt;I messed up, spectacularly. Luckily, it was in a test environment and not production, and there was nothing overly sensitive on my network.&lt;/p&gt;

&lt;p&gt;This is a mistake that I will not forget, and that I will bring with me in my career.&lt;/p&gt;

&lt;p&gt;There is no inherent issue with the tools that I used, or even a combination of tools, it was purely a configuration issue on my part. I would still 100% recommend all of the tools mentioned in this post, and intend to keep on using them. I have gained more respect for them, and intend to put them to use to further secure my network in the future.&lt;/p&gt;

&lt;h4&gt;
  
  
  Future Thoughts:
&lt;/h4&gt;

&lt;p&gt;As I rebuild my lab with a focus on Kubernetes and Zero Trust network design, the lessons I learned here will guide me in ensuring that everything is as secure as possible.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>keycloak</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Keycloak SSO Part 2: Setting up Keycloak</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Wed, 24 Apr 2019 01:25:48 +0000</pubDate>
      <link>https://dev.to/just_insane/keycloak-sso-part-2-setting-up-keycloak-e8p</link>
      <guid>https://dev.to/just_insane/keycloak-sso-part-2-setting-up-keycloak-e8p</guid>
      <description>&lt;p&gt;In part two of this series, we are going to look at setting up a standalone-ha deployment of Keycloak on two CentOS 7 servers.&lt;/p&gt;

&lt;p&gt;There are three different deployment types for Keycloak, Standalone, Standalone-HA, and Domain Clustered. Standalone deployments are single servers, this is good for a dev or test environment, but not very useful for production use. Standalone-HA are one or more servers which can both be used to serve authentication requests. This method requires a shared database, and each server is configured manually. In a Domain deployment, there is a master server known as the domain controller, and one or more host controllers which serve authentication requests. This mode allows the host controllers to all have an updated configuration when it is changed on the domain controller, greatly reducing administration overhead with multiple servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Hardware requirements, as well as distribution directory structure and operation mode information can be found at &lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#installation"&gt;https://www.keycloak.org/docs/latest/server_installation/index.html#installation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use Ansible to deploy the folder structure for Keycloak and make sure all dependencies are setup correctly. This allows me to easily update and ensure that all my Keycloak servers are deployed correctly. My playbook calls &lt;a href="https://github.com/andrewrothstein/ansible-keycloak"&gt;https://github.com/andrewrothstein/ansible-keycloak&lt;/a&gt; with some configuration file changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;Reading and understanding the official documentation is essential to installing Keycloak in a secure manner, I highly recommend you follow the information there and use my configuration as a guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operation Mode
&lt;/h3&gt;

&lt;p&gt;The first thing to think about when deploying Keycloak is what operation mode you want to use. This will mostly come down to your environment, and the configuration of most modes is the same, just within different files. I am most experienced with Standalone-HA mode, so that is what we are going to work with in this series.&lt;/p&gt;

&lt;p&gt;Configuration for this mode is done in the standalone-ha.xml configuration file found at &lt;code&gt;$keycloak_home/standalone/configuration/standalone-ha.xml&lt;/code&gt;. This file needs to be edited on all servers in a standalone-ha cluster setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relational Database Setup
&lt;/h3&gt;

&lt;p&gt;The next thing we have to do is setup Keycloak to use a database, since we are going to be creating a deployment with multiple servers, we are going to need a shared database. Setting up a centrally accessible database is beyond the scope of this article. Just know that we are going to be using a PostgreSQL database that is hosted outside of both of the Keycloak servers.&lt;/p&gt;

&lt;h4&gt;
  
  
  Download a JDBC driver
&lt;/h4&gt;

&lt;p&gt;The first step in setting up a database for Keycloak is to download a JDBC driver for the database. This allows Java to interact with the database. You can usually find these on the main site of your chosen database. For example, PostgreSQL's JDBC driver can be found here: &lt;a href="https://jdbc.postgresql.org/download.html"&gt;https://jdbc.postgresql.org/download.html&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Package the driver JAR and install
&lt;/h4&gt;

&lt;p&gt;The official documentation is a good resource for how to package the driver for use with Keycloak, and there is no point in duplicating efforts. It can be found here: &lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#package-the-jdbc-driver"&gt;https://www.keycloak.org/docs/latest/server_installation/index.html#package-the-jdbc-driver&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This boils down to adding a folder structure, copying the .jar file, and adding an .xml file like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" ?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;module&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:jboss:module:1.3"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.postgresql"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;resource-root&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"postgresql-9.4.1212.jar"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- update the filename to match your PostgreSQL JDBC driver file name --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"javax.api"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;module&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"javax.transaction.api"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Making sure to update the path with the correct file name.&lt;/p&gt;

&lt;h4&gt;
  
  
  Declare and load the driver
&lt;/h4&gt;

&lt;p&gt;This part, as well as modifying the datasource are a bit more advanced, so I will go over them in a bit more detail here, however the documentation is still very helpful.&lt;/p&gt;

&lt;p&gt;We are going to look at the standalone-ha.xml file we were working on earlier, specifically the &lt;code&gt;drivers&lt;/code&gt; XML block. In this block, we will be adding an additional driver. We can mostly copy the existing format of the h2 driver, and update the information for PostgreSQL. Below is an example of a driver in &lt;code&gt;standalone-ha.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;drivers&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;driver&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"h2"&lt;/span&gt; &lt;span class="na"&gt;module=&lt;/span&gt;&lt;span class="s"&gt;"com.h2database.h2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;xa-datasource-class&amp;gt;&lt;/span&gt;org.h2.jdbcx.JdbcDataSource&lt;span class="nt"&gt;&amp;lt;/xa-datasource-class&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/driver&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;driver&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"postgresql"&lt;/span&gt; &lt;span class="na"&gt;module=&lt;/span&gt;&lt;span class="s"&gt;"org.postgresql"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;xa-datasource-class&amp;gt;&lt;/span&gt;org.postgresql.xa.PGXADataSource&lt;span class="nt"&gt;&amp;lt;/xa-datasource-class&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/driver&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/drivers&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, the declaration of the driver is nearly identical to the pre-configured H2 database driver.&lt;/p&gt;

&lt;h4&gt;
  
  
  Modify the Keycloak Datasource
&lt;/h4&gt;

&lt;p&gt;Below we will see an example of a working PostgreSQL datasource configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;datasource&lt;/span&gt; &lt;span class="na"&gt;jndi-name=&lt;/span&gt;&lt;span class="s"&gt;"java:jboss/datasources/KeycloakDS"&lt;/span&gt; &lt;span class="na"&gt;pool-name=&lt;/span&gt;&lt;span class="s"&gt;"KeycloakDS"&lt;/span&gt; &lt;span class="na"&gt;enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;use-java-context=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;connection-url&amp;gt;&lt;/span&gt;jdbc:postgresql://$URL:$PORT/$DATABASE&lt;span class="nt"&gt;&amp;lt;/connection-url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;driver&amp;gt;&lt;/span&gt;postgresql&lt;span class="nt"&gt;&amp;lt;/driver&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;pool&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;max-pool-size&amp;gt;&lt;/span&gt;20&lt;span class="nt"&gt;&amp;lt;/max-pool-size&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/pool&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;security&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;user-name&amp;gt;&lt;/span&gt;$USERNAME&lt;span class="nt"&gt;&amp;lt;/user-name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;password&amp;gt;&lt;/span&gt;$PASSWORD&lt;span class="nt"&gt;&amp;lt;/password&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/security&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/datasource&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;$URL = The URL or IP Address of the PostgreSQL server&lt;br&gt;&lt;br&gt;
$PORT = The port to connect to PostgreSQL database&lt;br&gt;&lt;br&gt;
$DATABASE = The name of the database that is configured for Keycloak&lt;br&gt;&lt;br&gt;
$USERNAME = The username that has access to the database specified above&lt;br&gt;&lt;br&gt;
$PASSWORD = The password of the user defined above  &lt;/p&gt;

&lt;p&gt;In the end, you should end up with a &lt;code&gt;datasources&lt;/code&gt; section that looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;subsystem&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:jboss:domain:datasources:5.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;datasources&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;datasource&lt;/span&gt; &lt;span class="na"&gt;jndi-name=&lt;/span&gt;&lt;span class="s"&gt;"java:jboss/datasources/KeycloakDS"&lt;/span&gt; &lt;span class="na"&gt;pool-name=&lt;/span&gt;&lt;span class="s"&gt;"KeycloakDS"&lt;/span&gt; &lt;span class="na"&gt;enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;use-java-context=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;connection-url&amp;gt;&lt;/span&gt;jdbc:postgresql://$URL:$PORT/$DATABASE&lt;span class="nt"&gt;&amp;lt;/connection-url&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;driver&amp;gt;&lt;/span&gt;postgresql&lt;span class="nt"&gt;&amp;lt;/driver&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;pool&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;max-pool-size&amp;gt;&lt;/span&gt;20&lt;span class="nt"&gt;&amp;lt;/max-pool-size&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/pool&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;security&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;user-name&amp;gt;&lt;/span&gt;$USERNAME&lt;span class="nt"&gt;&amp;lt;/user-name&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;password&amp;gt;&lt;/span&gt;$PASSWORD&lt;span class="nt"&gt;&amp;lt;/password&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/security&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/datasource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;drivers&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;driver&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"h2"&lt;/span&gt; &lt;span class="na"&gt;module=&lt;/span&gt;&lt;span class="s"&gt;"com.h2database.h2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;xa-datasource-class&amp;gt;&lt;/span&gt;org.h2.jdbcx.JdbcDataSource&lt;span class="nt"&gt;&amp;lt;/xa-datasource-class&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/driver&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;driver&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"postgresql"&lt;/span&gt; &lt;span class="na"&gt;module=&lt;/span&gt;&lt;span class="s"&gt;"org.postgresql"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;xa-datasource-class&amp;gt;&lt;/span&gt;org.postgresql.xa.PGXADataSource&lt;span class="nt"&gt;&amp;lt;/xa-datasource-class&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/driver&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/drivers&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/datasources&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/subsystem&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Clustering
&lt;/h2&gt;

&lt;p&gt;The above steps will get a basic setup going with a shared database, however to properly cluster Keycloak, there are a few more steps that need to be completed.&lt;/p&gt;

&lt;p&gt;The relevent sections from the Keycloak documentation is below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#_operating-mode"&gt;Pick an operation mode&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#_database"&gt;Configure a shared external database&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#_setting-up-a-load-balancer-or-proxy"&gt;Set up a load balancer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.keycloak.org/docs/latest/server_installation/index.html#multicast-network-setup"&gt;Supplying a private network that supports IP multicast&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have already completed steps 1 and 2 in setting up a cluster. There are some additional setup needed for the next two operations, parts of which are made serviceable here, but are covered in more detail at the above links.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up a load balancer
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Identifying client IP addresses
&lt;/h4&gt;

&lt;p&gt;It is very important that Keycloak is able to identify client IP addresses for various reasons, which are explained further in the docs. We will go over the changes that have to be made in &lt;code&gt;standalone-ha.xml&lt;/code&gt; here.&lt;/p&gt;

&lt;p&gt;You will need to configure the &lt;code&gt;urn:jboss:domain:undertow:6.0&lt;/code&gt; block to look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;subsystem&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:jboss:domain:undertow:6.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;buffer-cache&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;server&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"default-server"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ajp-listener&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ajp"&lt;/span&gt; &lt;span class="na"&gt;socket-binding=&lt;/span&gt;&lt;span class="s"&gt;"ajp"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;http-listener&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt; &lt;span class="na"&gt;socket-binding=&lt;/span&gt;&lt;span class="s"&gt;"http"&lt;/span&gt; &lt;span class="na"&gt;redirect-socket=&lt;/span&gt;&lt;span class="s"&gt;"https"&lt;/span&gt; &lt;span class="na"&gt;proxy-address-forwarding=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      ...
   &lt;span class="nt"&gt;&amp;lt;/server&amp;gt;&lt;/span&gt;
   ...
&lt;span class="nt"&gt;&amp;lt;/subsystem&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enable HTTPS with a Reverse Proxy
&lt;/h4&gt;

&lt;p&gt;If you have a reverse proxy in front of Keycloak which handles your SSL connections and terminations, you need to make the following changes:&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;urn:jboss:domain:undertow:6.0&lt;/code&gt; block (configured above) change the &lt;code&gt;redirect-socket&lt;/code&gt; from https to a socket binding which we will define.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;subsystem&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:jboss:domain:undertow:6.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;http-listener&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"default"&lt;/span&gt; &lt;span class="na"&gt;socket-binding=&lt;/span&gt;&lt;span class="s"&gt;"http"&lt;/span&gt;
        &lt;span class="na"&gt;proxy-address-forwarding=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;redirect-socket=&lt;/span&gt;&lt;span class="s"&gt;"proxy-https"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/subsystem&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will now need to add a new socket binding to the &lt;code&gt;socket-binding-group&lt;/code&gt; element, like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;socket-binding-group&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"standard-sockets"&lt;/span&gt; &lt;span class="na"&gt;default-interface=&lt;/span&gt;&lt;span class="s"&gt;"public"&lt;/span&gt;
    &lt;span class="na"&gt;port-offset=&lt;/span&gt;&lt;span class="s"&gt;"${jboss.socket.binding.port-offset:0}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;socket-binding&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"proxy-https"&lt;/span&gt; &lt;span class="na"&gt;port=&lt;/span&gt;&lt;span class="s"&gt;"443"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/socket-binding-group&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the Cluster
&lt;/h2&gt;

&lt;p&gt;Once the changes have been made on all of your Keycloak servers, we can manually start the Keycloak servers in any order. The command for doing so is&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bin/standalone.sh --server-config=standalone-ha.xml&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 from the Keycloak home directory. The Keycloak servers will automatically configure themselves if they are connected to the same external database, and you can use your load balancer or reverse proxy to connect to either server to perform authentication operations.&lt;/p&gt;
&lt;h3&gt;
  
  
  Firewall
&lt;/h3&gt;

&lt;p&gt;Ensure you have configured the firewall correctly, Keycloak listens on ports 8080 and 8443 by default. There may be additional ports that need to be opened based on your configuration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running at boot
&lt;/h2&gt;

&lt;p&gt;Assuming your tests have passed and you can reach both of your Keycloak servers directly and through your load balancer, you are ready to setup a systemd unit file and have Keycloak start at boot.&lt;/p&gt;

&lt;p&gt;Below is a copy of the systemd unit file I am using, which is placed at &lt;code&gt;/etc/systemd/system/keycloak.service&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=Keycloak Identity Provider
After=syslog.target network.target
Before=httpd.service

[Service]
Environment=LAUNCH_JBOSS_IN_BACKGROUND=1 JAVA_HOME=/usr/local/java
User=keycloak
Group=keycloak
LimitNOFILE=102642
PIDFile=/var/run/keycloak/keycloak.pid
ExecStart=/usr/local/keycloak/bin/standalone.sh --server-config=standalone-ha.xml
#StandardOutput=null

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have completed this step, you can start and enable the service by running the below commands on all of your Keycloak servers:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;systemctl enable keycloak&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;systemctl start keycloak&lt;/code&gt;&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>sso</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Keycloak SSO Part 1: What is single sign on?</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Thu, 06 Dec 2018 21:00:00 +0000</pubDate>
      <link>https://dev.to/just_insane/keycloak-sso-part-1-what-is-single-sign-on-57gf</link>
      <guid>https://dev.to/just_insane/keycloak-sso-part-1-what-is-single-sign-on-57gf</guid>
      <description>&lt;p&gt;In this series, we will take a look at Keycloak, an open-source single sign on solution similar to Microsoft's ADFS product.&lt;/p&gt;

&lt;p&gt;In this first part, we will take a brief look at what SSO and Keycloak are, and why they are used.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Single Sign On
&lt;/h2&gt;

&lt;p&gt;Single sign-on (SSO) is a property of access control of multiple related, yet independent, software systems. &lt;a href="https://en.m.wikipedia.org/wiki/Single_sign-on"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What this means is that we can use a single authentication service to allow users to login to other services, without providing a password to the service that is being logged into.&lt;/p&gt;

&lt;p&gt;This is different than connecting each of these applications to LDAP, as this requires providing a username and password to every service that you want to login to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of SSO
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Central location for authentication allows for easier auditing and security.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Central location for configuration of authorization, ie, Jane is able to access email but not the CRM suite&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Authentication to external services such as a hosted CRM suite are made possible without sending LDAP requests over the internet&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tokens are wrapped in SSL/TLS as part of the HTTPS connection, but can also be both signed and/or encrypted using keys known only between the identity provider and service for increased security&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Keycloak
&lt;/h2&gt;

&lt;p&gt;Keycloak is an open source program that allows you to setup a secure single sign on provider. It supports multiple protocols such as SAML 2.0 and OpenID Connect. It can also store user credentials locally or via an LDAP or Kerberos backend.&lt;/p&gt;

&lt;p&gt;These features allows Keycloak to be highly configurable, but also fairly easy to install and setup.&lt;/p&gt;

&lt;p&gt;More information about Keycloak can be found here: &lt;a href="https://www.keycloak.org"&gt;https://www.keycloak.org&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Workflow
&lt;/h3&gt;

&lt;p&gt;The basic workflow when authenticating to a service that uses SAML/OIDC from the users perspective is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;User goes to the web address of a SSO protected service (known as a service provider, or SP).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The service asks for a cookie that the users browser may have stored, which contains a token, if it finds a valid token in the browser, it logs the user in. If this token does not exist, or is invalid, the service directs the user to the configured Identity Provider (IDp).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once the user reaches the IDp, they are presented with a login page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user logins in with their provided credentials. The IDp can compare these to locally stored credentials, or against an LDAP or Kerberos backend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user is given a token upon successful login which is stored as a cookie in the browser, and gets automatically redirected back to the service they were initially attempting to access. This token usually contains a username, as well as information regarding what the user has access to, if using a protocol like OIDC that supports authorization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The service requests the token from the browser and if the token is valid, allows the user access to the service.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Token validation is done on a secure back channel between the service and Identity Provider, without involving the browser, to increase security.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>sso</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Backing up FreeNAS to Backblaze B2</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Wed, 27 Sep 2017 23:09:00 +0000</pubDate>
      <link>https://dev.to/just_insane/backing-up-freenas-to-backblaze-b2-1ajh</link>
      <guid>https://dev.to/just_insane/backing-up-freenas-to-backblaze-b2-1ajh</guid>
      <description>&lt;p&gt;If you use FreeNAS, it’s probably because you care about your data. Part of data security is ensuring the availability of your data. To that end, you need to ensure that said data is backed up. There are generally two reasonable ways to backup your data from FreeNAS. One, local backup (using ZFS replication), and two, cloud backup.&lt;/p&gt;

&lt;p&gt;In this article, we will look at setting up cloud backups to Backblaze B2, an economical cloud backup solution similar to Amazon S3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Sign up
&lt;/h2&gt;

&lt;p&gt;Sign up for a Backblaze account &lt;a href="https://www.backblaze.com/b2/sign-up.html"&gt;here&lt;/a&gt;. Once you have created an account, go to the “My Settings” tab, and under “Enabled Products”, check the box beside B2 Cloud Storage. This enables your account for using B2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a Bucket
&lt;/h2&gt;

&lt;p&gt;Once you have enabled your account for B2, you need to create a bucket (where your files are stored). To do this, on the left side of the screen, select “Buckets” under B2 Cloud Storage. Then, select Create a Bucket. Also on this page, be sure to click on “Show Account ID and Application Key”, and mark down your Account ID and click “Create Application Key”. Also mark this down, as you will not be able to see it again, and will need it when we setup rclone in a later step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2a: Setup Caps and Alerts
&lt;/h3&gt;

&lt;p&gt;While this step is optional, it is highly recommended so that you get notified about any charges against your account that you may not be expecting. I set mine to a cap of $1 a day for each section. This will give you 6Tb of storage, and a good number of API calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2b: Have a look around your account
&lt;/h3&gt;

&lt;p&gt;Have a look around your Backblaze account, there is a great get started guide available &lt;a href="https://www.backblaze.com/b2/docs/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Setting up a FreeBSD Jail on FreeNAS
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Login to your FreeNAS GUI, and go to the Jails section.&lt;/li&gt;
&lt;li&gt;Click “Add Jail”.&lt;/li&gt;
&lt;li&gt;Enter a Jail Name. I called mine “b2-backups”.&lt;/li&gt;
&lt;li&gt;Click Ok, and your jail will be created. Note that this may take a little bit of time. You should be able to close the dialog box if needed, the jail will be created in the background.&lt;/li&gt;
&lt;li&gt;Click on your Jail and click the “shell” button in the bottom left. This will open a shell session to the Jail.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;vi /etc./rc.conf&lt;/code&gt; and change &lt;code&gt;sshd_enable="NO"&lt;/code&gt; to &lt;code&gt;sshd_enable="YES"&lt;/code&gt;. This will enable SSH to the jail.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;! FreeBSD uses vim as a text editor, use &lt;code&gt;i&lt;/code&gt; to insert text, &lt;code&gt;del&lt;/code&gt; to delete the rest of the line, and the arrow keys to scroll. Save and exit by pressing the &lt;code&gt;ESC&lt;/code&gt; key and then &lt;code&gt;:we&lt;/code&gt; to save and quit.&lt;/p&gt;

&lt;p&gt;! You will need to run &lt;code&gt;passwd root&lt;/code&gt; and reboot in order to have SSH access, as well as &lt;code&gt;PermitRootLogin yes&lt;/code&gt; in &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;!!!! At this point, you can switch over to SSH, if you prefer that to the shell in the FreeNAS GUI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;wget&lt;/code&gt; using &lt;code&gt;pkg install wget&lt;/code&gt;, this will allow you to download the rclone binary.&lt;/li&gt;
&lt;li&gt;Download the latest rclone binary: &lt;code&gt;cd /tmp &amp;amp;&amp;amp; wget https://downloads.rclone.org/rclone-v1.37-freebsd-amd64.zip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;unzip rclone-v1.37-freebsd-amd64.zip&lt;/code&gt; to extract the binary. !!!! rclone version 1.37 is the latest stable release at the time of this writing&lt;/li&gt;
&lt;li&gt;Copy the rclone executable to &lt;code&gt;/usr/bin&lt;/code&gt; by running &lt;code&gt;cd rclone-v1.37-freebsd-amd64 &amp;amp;&amp;amp; cp ./rclone /usr/bin&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3a: Adding storage to the Jail
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new folder structure in the Jail, I put mine in &lt;code&gt;/mnt/storage&lt;/code&gt;, where you will mount your FreeNAS datastores. It is a good idea to make a folder for each dataset you want to mount.&lt;/li&gt;
&lt;li&gt;In the FreeNAS GUI, go to the Jails tab, and then the Storage sub-tab.&lt;/li&gt;
&lt;li&gt;Click “Add Storage”&lt;/li&gt;
&lt;li&gt;Select the Jail you want to add the storage to.&lt;/li&gt;
&lt;li&gt;Select the source dataset.&lt;/li&gt;
&lt;li&gt;Select the destination (this will be the folder structure in the jail that you created in Step 3a-1).&lt;/li&gt;
&lt;li&gt;Optionally select read-only.&lt;/li&gt;
&lt;li&gt;Leave “Create Directory” selected.&lt;/li&gt;
&lt;li&gt;Click “Ok”.&lt;/li&gt;
&lt;li&gt;Repeat steps 3a-4 to 3a-9 for each dataset you want to backup to B2.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Configuring rclone
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;rclone config&lt;/code&gt; to initiate the configuration of rclone&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;n&lt;/code&gt; to create a new remote (a remote is what rclone uses to know where to copy/sync your files).&lt;/li&gt;
&lt;li&gt;Enter a name, I choose &lt;code&gt;b2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter your account ID from your B2 account.&lt;/li&gt;
&lt;li&gt;Enter your application Key from your B2 account.&lt;/li&gt;
&lt;li&gt;Leave endpoint blank.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;y&lt;/code&gt; to save the config.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4a: Configuring encryption
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Follow steps 1-3 from Step 4. ! Note, name this new remote different than the previous remote.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;5&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter the name of the remote you created in Step 4, number 3, followed by the name of your bucket. For example, &lt;code&gt;b2:storage&lt;/code&gt; in my case.&lt;/li&gt;
&lt;li&gt;Choose whether or not you want to encrypt the file names, selecting &lt;code&gt;1&lt;/code&gt; does not encrypt file names. Selecting &lt;code&gt;2&lt;/code&gt; encrypts the file names. I choose &lt;code&gt;2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;y&lt;/code&gt; to type in your own password, choose &lt;code&gt;g&lt;/code&gt; to generate a strong password randomly. If you choose &lt;code&gt;g&lt;/code&gt;, you are given an option as to how strong of a password you want to generate.&lt;/li&gt;
&lt;li&gt;Create a password for the salt. This is recommended if you have chosen to enter your own password in the previous section. Note that for security, these passwords should not be the same.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;y&lt;/code&gt; to accept the configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;!! Note: The rclone config file is not encrypted by default, and Application Keys and your encryption passwords are stored in plaintext. It is recommended to set a password for the config file, and/or ensure the security of the rclone.conf file.&lt;/p&gt;

&lt;p&gt;!! If you need to recover encrypted files from B2, you NEED both passwords (if you set two), otherwise your files will be completely unrecoverable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4b: Creating the bash script
&lt;/h3&gt;

&lt;p&gt;In this section, we will look at creating the bash script we will use with cron in order to backup any changes to our local storage to B2.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new file in &lt;code&gt;/root&lt;/code&gt;, I called mine &lt;code&gt;rclone-cron.sh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;!/bin/sh&lt;br&gt;
if pidof -o %PPID -x "rclone-cron.sh"; then&lt;br&gt;
exit 1&lt;br&gt;
fi&lt;br&gt;
echo starting storage sync&lt;br&gt;
rclone copy {/path/to/local/storage} {name of your crypt remote}: -v --log-file={/path/to/log/file} --min-age 15m --copy-links&lt;br&gt;
exit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s break that down a bit and look at what the script actually does.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;!/bin/sh&lt;/code&gt; - run the script with the &lt;code&gt;sh&lt;/code&gt; terminal.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if pidof -o %PPID -x "rclone-cron.sh"; then&lt;/code&gt; - If the script is currently being run, then:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;exit 1&lt;/code&gt; - Do not run the script currently. This is good if your initial backup will take a while to run, as it won’t try to run rclone again.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fi&lt;/code&gt; - closes the if statement.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;echo start storage sync&lt;/code&gt; - print to the terminal that the clone is starting.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rclone copy {/path/to/local/storage} {name of your crypt remote}: -v --log-file={/path/to/log/file} --min-age 15m --copy-links&lt;/code&gt; - runs &lt;code&gt;rclone&lt;/code&gt; with the copy parameter (does not delete files deleted locally, alternatively change &lt;code&gt;copy&lt;/code&gt; to &lt;code&gt;sync&lt;/code&gt; to keep an exact copy on B2 (deletes files from B2 that are deleted locally)). Uses the &lt;code&gt;-v&lt;/code&gt; flag for verbosity. &lt;code&gt;--log-file={/path/to/log/file}&lt;/code&gt; Tells rclone where to create a log file. &lt;code&gt;--min-age 15m&lt;/code&gt; Tells rclone not to sync files less than 15 minutes old, useful to ensure copied files are probably complete, instead of semi-completed. &lt;code&gt;--copy-links&lt;/code&gt; Tells rclone to follow slinks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;exit&lt;/code&gt; - exits the script when the copy is finished.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4c: Creating the cron entry
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;crontab -e&lt;/code&gt; to open the cron editor.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;0 1 * * * /root/rclone-cron.sh&lt;/code&gt; - This will run the script we created in 4b once a day.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: Run the script!
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;chmod +x /root/rclone-cron.sh&lt;/code&gt; - makes the script executable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cd /root/ &amp;amp;&amp;amp; ./rclone-cron.sh&lt;/code&gt; - runs the script. ! rclone does not run in the background. It is recommended to run the script in tmux or similar, or wait for the crontab to run, as the initial backup will probably take a long time if you have a lot of data like I do.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 5a: Check B2 console to see if it’s working.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log into your back blaze account, and take a look at your bucket. You should see that files are being copied to B2.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This completes the guide on setting up rclone to backup to B2 on FreeNAS. Rclone can backup to many cloud providers, have a look at different providers if Backblaze is not your cup of tea.&lt;/p&gt;

</description>
      <category>freenas</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Nginx: Reverse Proxy</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Mon, 25 Sep 2017 02:00:00 +0000</pubDate>
      <link>https://dev.to/just_insane/nginx-reverse-proxy-300p</link>
      <guid>https://dev.to/just_insane/nginx-reverse-proxy-300p</guid>
      <description>&lt;p&gt;In this article we will look at what a reverse proxy is, as well as how to set one up on CentOS using Nginx.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Reverse Proxy
&lt;/h2&gt;

&lt;p&gt;A reverse proxy is a type of proxy server which retrieves resources on behalf of a client, from one or more servers. The collected information is then returend to the client as if it originated from the web server itself. It is the opposite of a forward proxy (one which allows it’s clients to contact any server), a reverse proxy allows it’s servers to be contacted by any client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I need a Reverse Proxy
&lt;/h2&gt;

&lt;p&gt;You would need a reverse proxy for a number of potential use cases. The most common reason to use a reverse proxy is to increase security. For example, a reverse proxy can be a hardend computer in your DMZ, which then takes client traffic from the internet, and passes it to your internal web application servers. This would have two main security benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lower attack surface: Each system you expose to the internet increases the attack surface to get into your network. It only takes the compromise of one of those systems to wreak havoc on all of your internal systems.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Easier to patch/manage/secure: Having less resources exposed to the internet also means that you have less critial infrastructure to patch, manage, and secure. Of course, you should still definitely be doing patches on your internal systems, however, the best security is defence in depth, basically, having as many hard layers to go through before the attack is able to breach your inner network. Having a reverse proxy increases the number of layers before getting into your network.&lt;/p&gt;

&lt;p&gt;Another reason you would want to setup a reverse proxy is if you have a number of resources inside your network, such as web and application servers/services, which you want to all be accessable outside of your network, but you only have one public IP address. Instead of having websites on different services, you can put all of those sites behind your reverse proxy on one IP and port (80/443), and then have clients connect to the proper backend based on the (sub)domain on which they are trying to connect.&lt;/p&gt;

&lt;p&gt;Reverse Proxies also decrease your management costs, for example, instead of getting an SSL certificate and installing it on every web server you have, and then managing all of those certificates, you can get one certificate (either wildcard or SAN), and install it on your reverse proxy. This way, all traffic between the client and web server is encryted, but you don’t have to spend extra time and money dealing with installing certificates on each service behind the proxy. Note however, that doing this means that traffic between the reverse proxy and web server (inside your network) is unencrypted, unless you configure the internal site for HTTPS. This is usually not a big deal for a homelab environment or testing, but please be advised that it is less secure and should not be used in production environment. If you are in a production environment, ensure that traffic is encrypted between the reverse proxy and the internal application server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Reverse Proxy should I use
&lt;/h2&gt;

&lt;p&gt;There are many types of reverse proxies, from dedicated enterprise hardware/software like F5 Big-IPs, all the way down to a regular web server, like Nginx or Apache. Each of these will have different Pros and Cons, which you should research yourself. However, for a small blog or homelab environment, a reverse proxy running Nginx will be fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Nginx as a Reverse Proxy
&lt;/h2&gt;

&lt;p&gt;Now that we have looked at what a Reverse Proxy is, and why we might want to use one, lets look at installing Nginx as a reverse proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Installing Nginx
&lt;/h3&gt;

&lt;p&gt;In this step, we will look at installing Nginx on CentOS 7. Note that these steps should be similar for your prefered distribution, however, I make no promises.&lt;/p&gt;

&lt;p&gt;First, update packages on your CentOS server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo yum -y update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo yum -y install nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Nginx and enable (so that it starts at boot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo systemctl start nginx
$ sudo systemctl enable nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that Nginx is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Nginx is running, we need to open the firewall so that our clients can access it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have done that, we should verify that we are actually able to reach nginx. Go to &lt;code&gt;http://&amp;lt;ip_of_your_host&amp;gt;&lt;/code&gt; in a web browser, and you should get an Nginx page. If you do not, ensure that Nginx is running, and that you have opened the firewall.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configuring Nginx
&lt;/h3&gt;

&lt;p&gt;In this step, we will configure some sane defaults for our Nginx installation, including SSL and Proxy defaults.&lt;/p&gt;

&lt;p&gt;First, let’s look at using Nginx’s snippets feature to configure the default SSL and Proxy settings in Nginx.&lt;/p&gt;

&lt;h4&gt;
  
  
  Proxy Defaults
&lt;/h4&gt;

&lt;p&gt;In &lt;code&gt;/etc/nginx/snippets/&lt;/code&gt;, create a file called &lt;code&gt;proxy-defaults.conf&lt;/code&gt;, with the contents of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add &lt;code&gt;include snippets/proxy-defaults.conf&lt;/code&gt; to your server block.&lt;/p&gt;

&lt;h4&gt;
  
  
  SSL Defaults
&lt;/h4&gt;

&lt;p&gt;First, let’s take a look at setting up the SSL certificates and dhparam files needed.&lt;/p&gt;

&lt;h5&gt;
  
  
  Getting an SSL certificate
&lt;/h5&gt;

&lt;p&gt;We will look at setting up Let’s Encrypt, a free certificate authority.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 1 - Installing the Certbot Let’s Encrypt Client
&lt;/h6&gt;

&lt;p&gt;Enable the EPEL repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo yum -y install epel-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install certbot-nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo yum -y install certbot-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Cerbot to work, you need to specify your server name in &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo vi /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the existing &lt;code&gt;server_name&lt;/code&gt; line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server_name _;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;_&lt;/code&gt; underscore with your domain name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server_name example.com www.example.com;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that the syntax of the configuration file is correct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo nginx -t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this completes without errors, reload Nginx to load the new configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  Step 2 - Obtaining a Certificate
&lt;/h6&gt;

&lt;p&gt;There are a number of ways to obtain certificates from Let’s Encrypt through Certbot. We will use the Nginx plugin to take care of reconfiguring Nginx and reloading the config when certificates are updated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo certbot --nginx --rsa-key-size 4096 -d example.com -d www.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will run &lt;code&gt;certbot&lt;/code&gt; with the &lt;code&gt;--nginx&lt;/code&gt; plugin, a key size of 4096 (more secure than the default 2048), and use &lt;code&gt;-d&lt;/code&gt; to specify the domain names we would like the certificate to be valid for.&lt;/p&gt;

&lt;p&gt;! You need to add every sub-domain you want to use Let’s Encrypt certificates, seperated with the &lt;code&gt;-d&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;If this is the first time you’ve run certbot on this server, you will be prompted to enter an email address and agree to the terms of service. It will then test to ensure that it can communicate with Let’s Encrypt’s servers.&lt;/p&gt;

&lt;p&gt;Once that is complete, you will be asked how you’d like to configure HTTPS on your server. Choose the option you’d like to use, and then press Enter. You will then be told where your certificates are stored on the server.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 3 - Updating Diffie-Hellman Parameters
&lt;/h6&gt;

&lt;p&gt;Currently, if you test your server using the &lt;a href="https://www.ssllabs.com/ssltest/"&gt;SSL Labs test&lt;/a&gt;, you will notice that you only get a &lt;strong&gt;B&lt;/strong&gt; grade. We can fix this be creating a new dhparam.pem file and adding it to our &lt;code&gt;ssl-defaults.conf&lt;/code&gt; file (see the next section).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will take a while. Make note of where the dhparam.pem file is located, as it will be needed in the next step.&lt;/p&gt;

&lt;h6&gt;
  
  
  Step 4 - Setting Up Auto Renewal
&lt;/h6&gt;

&lt;p&gt;Let’s Encrypts certificates are only valid for ninety days. Therefore, we will need to setup a command to run regularly, which will check for expiring certificates and renew them automatically.&lt;/p&gt;

&lt;p&gt;We will run the certbot renewal command daily, using &lt;code&gt;cron&lt;/code&gt;. To do so, we need to edit a file called a &lt;code&gt;crontab&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo crontab -e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following line, then save and close the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;15 3 * * * /usr/bin/certbot renew --quiet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break that out and look at what the command is doing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;15 3 * * *&lt;/code&gt; - Run the following command at 3:15 am, every day. You may choose any time to run the command at.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/usr/bin/certbot&lt;/code&gt; - Calls the &lt;code&gt;certbot&lt;/code&gt; utility.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;renew&lt;/code&gt; - Tells Certbot to check all certificates installed on the system and update any that are set to expire in less than thirty days.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--quiet&lt;/code&gt; - Tells Certbot not to output information or wait for user input.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;cron&lt;/code&gt; will now run this command daily. All installed cerificates will be automatically renewed and reloaded when there is thirty or less days before they expire.&lt;/p&gt;

&lt;h5&gt;
  
  
  Creating the ssl-defaults.conf snippet
&lt;/h5&gt;

&lt;p&gt;In &lt;code&gt;/etc/nginx/snippets/&lt;/code&gt;, create a file called &lt;code&gt;ssl-defaults.conf&lt;/code&gt;, with the contents of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# These next two lines depend on where certbot placed your SSL certificates
# edit them to match the location of the files
# ssl_certificate /path/to/ssl/certificate
# ssl_certificate_key /path/to/ssl/certificate_key

ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
# The following setting can be dangerous, please research what it does before uncommenting.
# add_header Strict-Transport-Security max-age=15768000;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add &lt;code&gt;include snippets/ssl-defaults.conf&lt;/code&gt; to your server block.&lt;/p&gt;

&lt;p&gt;!! Note: These defaults may not fit your needs in every case. You may have to configure different settings in your server block.&lt;/p&gt;

&lt;p&gt;! Also note that if you need to change these default settings, just remove &lt;code&gt;include snippets/&amp;lt;item&amp;gt;-defaults.conf&lt;/code&gt; from the server block.&lt;/p&gt;

&lt;p&gt;These default settings allow you to get an A+ from &lt;a href="https://www.ssllabs.com/ssltest/index.html"&gt;SSLLabs&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Default Server Block Template
&lt;/h4&gt;

&lt;p&gt;Server blocks should be added to &lt;code&gt;/etc/nginx/sites-available&lt;/code&gt;. The file should be named &lt;code&gt;&amp;lt;subdomain&amp;gt;.example.com.conf&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen 443 ssl;
    server_name www.example.com;
    ssl on;
        # Remember to comment these out if you need to change their defaults
        include snippets/ssl-defaults.conf;
        include snippets/proxy-defaults.conf;

    location / {
        proxy_pass http://&amp;lt;internal_ip&amp;gt;:&amp;lt;port&amp;gt;/;
        # Input any other settings you may need that are not already contained in the default snippets.
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating your server block, you need to link it to &lt;code&gt;/etc/nginx/sites-enabled/&lt;/code&gt; using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo ln -s /etc/nginx/sites-available/www.example.com.conf /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test the Nginx config using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ nginx -t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have configured all of these settings, you need to reload nginx, so that it has the new config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ systemctl reload nignx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to reach your internal site from the internet.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Ansible Part 2: Installing Telegraf</title>
      <dc:creator>Jax Gauthier</dc:creator>
      <pubDate>Sat, 23 Sep 2017 04:00:00 +0000</pubDate>
      <link>https://dev.to/just_insane/ansible-part-2-installing-telegraf-32b8</link>
      <guid>https://dev.to/just_insane/ansible-part-2-installing-telegraf-32b8</guid>
      <description>&lt;p&gt;In part two of this series, we will look at creating a playbook to deploy and configure Telegraf, the popular devops service for getting your system’s metrics into a time series database, for use with tools like Grafana.&lt;/p&gt;

&lt;p&gt;As always, a link to the completed playbook can be found &lt;del&gt;&lt;a href="https://git.justin-tech.com/snippets/13"&gt;here&lt;/a&gt;&lt;/del&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- hosts: all

  tasks:
  - name: Add telegraf repository
    yum_repository:
      name: influxdb
      description: InfluxDB Repository - RHEL $releasever
      baseurl: https://repos.influxdata.com/rhel/$releasever/$basearch/stable
      gpgcheck: yes
      gpgkey: https://repos.influxdata.com/influxdb.key

  - name: Install telegraf
    yum:
      name: telegraf
      state: latest

  - name: Copy config
    copy:
      src: ./telegraf.conf
      dest: /etc/telegraf/telegraf.conf
      owner: root
      group: root
      mode: 0644
      backup: yes
      force: no
      notify:
      - restart telegraf

  handlers:
  - name: restart telegraf
    service:
      name: telegraf
      state: restarted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This playbook is a bit more advanced then the last one we looked at, however, it gives you a good overview on the structure of a simple playbook, and how to define multiple tasks.&lt;/p&gt;

&lt;p&gt;Let’s break it down below.&lt;/p&gt;

&lt;p&gt;! Note that I won’t explain parts that are the same across this playbook and the previous, which can be found &lt;a href="https://homelab.blog/blog/configuration%20management/ansible-part-1-linux-host-updates/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we can see that there are three tasks, and a handler defined. Handlers are a way to tell Ansible to do &lt;code&gt;&amp;lt;something&amp;gt;&lt;/code&gt;, but only when a task actually changes or updates something. In this playbook, the handler tells Ansible to restart telegraf if the final task in the playbook makes a change, otherwise telegraf won’t be restarted.&lt;/p&gt;

&lt;p&gt;Second, let’s look at the first task. Called “Add telegraf repository”, in this task, we will find a new component of Ansible, called “yum_repository”, which will add a Yum repository to our system. Below that, we will see the vairables that are used for the repository. These are what gets added to the .repo file, and are based on the repository we are trying to add. In this file, you will see the information needed to install Telegraf.&lt;/p&gt;

&lt;p&gt;Third, in the second task, you will see that we are again using the yum module to install a system service. For more information, please see the previous blog post in this series.&lt;/p&gt;

&lt;p&gt;Fourth, we will find a task called “Copy config”, and as it sounds, it will copy a pre-made telegraf.conf file into the correct location for use by telegraf. Let’s take a further look at it.&lt;/p&gt;

&lt;p&gt;This task is also using a new module called copy, and below that, we can see some of the available variables for the module. The first five lines are pretty basic, they define the source location for the file, the destination on the remote system, as well as the owner and permissons on the file. The next three lines are a bit more advanced.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backup&lt;/code&gt; tells Ansible to “Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly”, this is very important if you are overwriting configuration files for programs, in the case that something breaks, you can always revert to the default configuration file if one exists.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;force: no&lt;/code&gt; tells Ansible to only copy the file to the remote system if it does not already exist. “The default is yes, which will replace the remote file when contents are different than the source. If no, the file will only be transferred if the destination does not exist.” In my case, this file should not be changing once it’s on the remote system, setting force to no saves me a couple of seconds off the total run time of the playbook, and if I do ever change the conf file, I can easily change or remove the force variable from the playbook.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;notify&lt;/code&gt; This is an interesting argument, but one that is very important to creating a strong playbook in Ansible. As I mentioned previously, the notify command can be used to call handlers. Handlers can do many things, but in this playbook, we only use them to programatically tell Ansible if we want to restart the telegraf service. If you want to learn more about Handlers, please see the Ansible documentation &lt;a href="http://docs.ansible.com/ansible/latest/playbooks_intro.html#handlers-running-operations-on-change"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we will look at the handlers section of the playbook. As you can see, the handler’s section looks very similar to a task, and that’s because it is. They are tasks that only run when you call them when something is changed. In our example, it doesn’t make sense to restart telegraf every single time the playbook is run, as this leads to downtime in our metrics, and that is generally not a good thing, and leads to a lot of alerts being sent out (you have alerts setup, right?).&lt;/p&gt;

&lt;p&gt;This completes our post on using Ansible to setup Telegraf, as well as looking at a slightly more advanced playbook then we did previously.&lt;/p&gt;

&lt;p&gt;P.S. If you want to see what you can do with Grafana and system metrics, try pressing the “Dashboard” button in the top left of the page, or going to &lt;del&gt;&lt;a href="https://dashboard.justin-tech.com"&gt;https://dashboard.justin-tech.com&lt;/a&gt;&lt;/del&gt;&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>dev</category>
    </item>
  </channel>
</rss>
