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

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

--

--

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