Adding authentication to Kubernetes app using Keycloak and the new oauth2-proxy

Configuring Keycloak

Deploying the application

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: oauth2-proxy
image: carlosedp/oauth2-proxy:v7.0.0
imagePullPolicy: Always
args:
- --config=/etc/oauth2-proxy.cfg
ports:
- containerPort: 3000
name: web
volumeMounts:
- name: oauth2-proxy-config
mountPath: /etc/oauth2-proxy.cfg
subPath: oauth2-proxy.cfg
- name: oauth2-templates
mountPath: /templates
volumes:
- name: oauth2-proxy-config
configMap:
name: oauth2-proxy-config
- name: oauth2-templates
configMap:
name: oauth2-templates
---
apiVersion: v1
kind: ConfigMap
metadata:
name: oauth2-proxy-config
namespace: default
data:
oauth2-proxy.cfg: |+
# Provider config
provider="keycloak"
provider_display_name="Keycloak"
login_url="https://keycloak.192.168.1.170.nip.io:8443/auth/realms/Kubeapps/protocol/openid-connect/auth"
redeem_url="https://keycloak.192.168.1.170.nip.io:8443/auth/realms/Kubeapps/protocol/openid-connect/token"
validate_url="https://keycloak.192.168.1.170.nip.io:8443/auth/realms/Kubeapps/protocol/openid-connect/userinfo"
ssl_insecure_skip_verify=true
# Client config
client_id="kubernetes"
client_secret="f6c21649-9972-4da9-8f47-d66b64d207d1"
cookie_secret="OQINaROshtE9TcZkNAm5Zs2Pv3xaWytBmc5W7sPX7ws="
cookie_secure="false"
# Upstream config
http_address="0.0.0.0:3000"
upstreams="http://127.0.0.1:80/"
# Proxy Config
keycloak_group="/app1grp"
#user_id_claim="preferred_username"
skip_auth_routes=["/health.*"]
skip_provider_button="true"
reverse_proxy="true"
email_domains=["*"]
cookie_domains=[".nip.io"]
whitelist_domains=[".nip.io:*"]
custom_templates_dir="/templates"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: oauth2-templates
namespace: default
data:
sign_in.html: |+
<!DOCTYPE html> <html lang="en" charset="utf-8"> <head> <title>Sign In</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <style>body{font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; font-size: 14px; line-height: 1.42857143; color: #333; background: #f0f0f0;}.signin{display:block; margin:20px auto; max-width:400px; background: #fff; border:1px solid #ccc; border-radius: 10px; padding: 20px;}.center{text-align:center;}.btn{color: #fff; background-color: #428bca; border: 1px solid #357ebd; -webkit-border-radius: 4; -moz-border-radius: 4; border-radius: 4px; font-size: 14px; padding: 6px 12px; text-decoration: none; cursor: pointer;}.btn:hover{background-color: #3071a9; border-color: #285e8e; text-decoration: none;}label{display: inline-block; max-width: 100%; margin-bottom: 5px; font-weight: 700;}input{display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075); box-shadow: inset 0 1px 1px rgba(0,0,0,.075); -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; margin:0; box-sizing: border-box;}footer{display:block; font-size:10px; color:#aaa; text-align:center; margin-bottom:10px;}footer a{display:inline-block; height:25px; line-height:25px; color:#aaa; text-decoration:underline;}footer a:hover{color:#aaa;}</style> </head> <body> <div class="signin center"> <form method="GET" action="{{.ProxyPrefix}}/start"> <input type="hidden" name="rd" value="{{.Redirect}}">{{if .SignInMessage}}<p>{{.SignInMessage}}</p>{{end}}<button type="submit" class="btn">Sign in with{{.ProviderName}}</button><br/> </form> </div>{{if .CustomLogin}}<div class="signin"> <form method="POST" action="{{.ProxyPrefix}}/sign_in"> <input type="hidden" name="rd" value="{{.Redirect}}"> <label for="username">Username:</label><input type="text" name="username" id="username" size="10"><br/> <label for="password">Password:</label><input type="password" name="password" id="password" size="10"><br/> <button type="submit" class="btn">Sign In</button> </form> </div>{{end}}<script>if (window.location.hash){(function(){var inputs=document.getElementsByName('rd'); for (var i=0; i < inputs.length; i++){// Add hash, but make sure it is only added once var idx=inputs[i].value.indexOf('#'); if (idx >=0){// Remove existing hash from URL inputs[i].value=inputs[i].value.substr(0, idx);}inputs[i].value +=window.location.hash;}})();}</script> <footer>{{if eq .Footer "-"}}{{else if eq .Footer ""}}Secured with <a href="https://github.com/oauth2-proxy/oauth2-proxy#oauth2_proxy">OAuth2 Proxy</a> version{{.Version}}{{else}}{{.Footer}}{{end}}</footer> </body> </html>
error.html: |+
<html lang="en"><head> <title>Access Forbidden</title><style>*{font-family: "Courier", "Courier New", "sans-serif"; margin:0; padding: 0;}body{background: #233142;}.whistle{width: 20%; fill: #f95959; margin: 100px 40%; text-align: left; transform: translate(-50%, -50%); transform: rotate(0); transform-origin: 80% 30%; animation: wiggle .2s infinite;}@keyframes wiggle{0%{transform: rotate(3deg);}50%{transform: rotate(0deg);}100%{transform: rotate(3deg);}}h1{margin-top: -100px; margin-bottom: 20px; color: #facf5a; text-align: center; font-size: 90px; font-weight: 800;}h2, a{color: #455d7a; text-align: center; font-size: 30px; text-transform: uppercase;}</style> </head><body> <use> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve" class="whistle"><g><g transform="translate(0.000000,511.000000) scale(0.100000,-0.100000)"><path d="M4295.8,3963.2c-113-57.4-122.5-107.2-116.8-622.3l5.7-461.4l63.2-55.5c72.8-65.1,178.1-74.7,250.8-24.9c86.2,61.3,97.6,128.3,97.6,584c0,474.8-11.5,526.5-124.5,580.1C4393.4,4001.5,4372.4,4001.5,4295.8,3963.2z"/><path d="M3053.1,3134.2c-68.9-42.1-111-143.6-93.8-216.4c7.7-26.8,216.4-250.8,476.8-509.3c417.4-417.4,469.1-463.4,526.5-463.4c128.3,0,212.5,88.1,212.5,224c0,67-26.8,97.6-434.6,509.3c-241.2,241.2-459.5,449.9-488.2,465.3C3181.4,3180.1,3124,3178.2,3053.1,3134.2z"/><path d="M2653,1529.7C1644,1445.4,765.1,850,345.8-32.7C62.4-628.2,22.2-1317.4,234.8-1960.8C451.1-2621.3,947-3186.2,1584.6-3500.2c1018.6-501.6,2228.7-296.8,3040.5,515.1c317.8,317.8,561,723.7,670.1,1120.1c101.5,369.5,158.9,455.7,360,553.3c114.9,57.4,170.4,65.1,1487.7,229.8c752.5,93.8,1392,181.9,1420.7,193.4C8628.7-857.9,9900,1250.1,9900,1328.6c0,84.3-67,172.3-147.4,195.3c-51.7,15.3-790.8,19.1-2558,15.3l-2487.2-5.7l-55.5-63.2l-55.5-61.3v-344.6V719.8h-411.7h-411.7v325.5c0,509.3,11.5,499.7-616.5,494C2921,1537.3,2695.1,1533.5,2653,1529.7z"/></g></g></svg></use><h1>403</h1><h2>Not this time, access forbidden!</h2><h2><a href="{{.ProxyPrefix}}/sign_out?rd=https://keycloak.192.168.1.170.nip.io:8443/auth/realms/Kubeapps/protocol/openid-connect/logout?redirect_uri=https://google.com">Logout</h2></body></html>
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: web
selector:
app: nginx
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: test.192.168.1.170.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80

--

--

--

Writing everything cloud and all the tech behind it. If you like my projects and would like to support me, check my Patreon on https://www.patreon.com/carlosedp

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Practicing fortran — No_1

[C++] Object Oriented Programming (OOP)

The Importance of Field Testing

Why Choose Swift Over Objective C?

2019- And so it begins

WAX monthly update — July 2021

A Few Words About Queues

Minimum Spanning Tree

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Carlos Eduardo

Carlos Eduardo

Writing everything cloud and all the tech behind it. If you like my projects and would like to support me, check my Patreon on https://www.patreon.com/carlosedp

More from Medium

Setting up your K8 lab — Prerequisites

K8 Cluster configuration

Running containers in Openshift with custom SELinux type

Knative across multiple Kubernetes clusters with Liqo and Direktiv

About Kubernetes architecture(4); Helm