在 k8s 中授权外部应用程序的端点
在代码级别实现授权通常很简单。
类似地,公开具有内置身份验证支持的外部工具(例如 Grafana)也可以相对容易地处理。
真正的挑战出现在处理缺乏对身份验证或授权的本机支持的简单工具或服务时,需要外部机制来确保安全访问。
解决此问题的一种方法是限制通过 VPN 的访问或使用 IP 地址范围保护它,这仍然是最可靠的方法之一。
然而,我最近探索了一种替代方案:重用 Keycloak(我们已经在使用的 oauth 提供程序之一)来验证对特定端点的访问。
可能适用于此的工具是**OAuth2 Proxy**,它支持广泛的 OAuth 提供商,例如 Facebook、Google、GitLab 和 Azure。
额外的要求是将这些工具分组到单个 URL 下,例如 **tools.example.com/tool-name**,以简化访问和管理。
**oauth2-proxy 基本设置:**
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: oauth2-proxy
name: oauth2-proxy
namespace: default
spec:
replicas: 1
selector:
matchLabels:
k8s-app: oauth2-proxy
template:
metadata:
labels:
k8s-app: oauth2-proxy
spec:
containers:
- args:
- --provider=keycloak-oidc
- --oidc-issuer-url=https://{ISSUER_HOST}/realms/{REALM_NAME}
- --code-challenge-method=S256
- --allowed-role={ROLE}
- --email-domain=*
- --upstream=file:///dev/null
- --http-address=0.0.0.0:4180
- --client-id={CLIENT_ID}
- --client-secret={CLIENT_SECRET}
- --session-cookie-minimal
env:
- name: OAUTH2_PROXY_COOKIE_SECRET
value: {COOKIE_SECRET}
image: quay.io/oauth2-proxy/oauth2-proxy:latest
imagePullPolicy: Always
name: oauth2-proxy
ports:
- containerPort: 4180
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: oauth2-proxy
name: oauth2-proxy
namespace: default
spec:
ports:
- name: http
port: 4180
protocol: TCP
targetPort: 4180
selector:
k8s-app: oauth2-proxy**入口配置(假设您已经有一个名为 tools-example-com-tls 的 TLS 密钥)**
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tools
namespace: default
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 15m
spec:
ingressClassName: nginx
tls:
- hosts:
- "tools.example.com
secretName: tools-example-com-tls
rules:
- host: "tools.example.com"
http:
paths:
- path: /oauth2
pathType: Prefix
backend:
service:
name: oauth2-proxy
port:
number: 4180
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tools-external-auth-oauth2
namespace: default
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 15m
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- "tools.example.com"
secretName: tools-example-com-tls
rules:
- host: "tools.example.com"
http:
paths:
- path: /certificates
pathType: Prefix
backend:
service:
name: cert-checker
port:
number: 8081在我们的案例中,其中一个工具是证书检查器的仪表板。
**额外奖励:**
此外,我们的解决方案包括部署在遵循 s1-app、s2-app 等模式的地址的多个有状态服务,每个相应的服务都通过 ASP.NET 公开自己的工具实例。
例如,我们可能希望在**tools.example.com/s1/quartz**和**tools.example.com/s2/quartz**等地址公开相关的 quartz-ui 实例。

**鉴于此需求,Ingress 资源 tools-external-auth-oauth2 由多个路径组成,例如:**
- path: /s[0-9]+/quartz
pathType: ImplementationSpecific
backend:
service:
name: tools-nginx-reverse-proxy
port:
number: 80**nginx反向代理配置:**
apiVersion: v1
kind: ConfigMap
metadata:
name: tools-nginx-reverse-proxy-config
namespace: default
data:
nginx.conf: |
events {
worker_connections 1024;
}
http {
resolver 10.3.0.10 valid=10s; #KubeDNS or CoreDNS internal ip
server {
listen 80;
location ~ ^/s([0-9]+)/quartz{
set $service_name "s$1-app.default.svc.cluster.local";
rewrite ^/s([0-9]+)/quartz$ /quartz break;
proxy_pass http://$service_name:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_read_timeout 90;
proxy_send_timeout 90;
}
location ~ ^/s([0-9]+)/quartz/(.*\.(css|js|png|jpg|jpeg|gif|svg|woff2|woff|ttf))$ {
set $service_name "s$1-app.default.svc.cluster.local";
rewrite ^/s([0-9]+)/quartz/(.*)$ /$2 break;
proxy_pass http://$service_name:80;
}
location / {
return 404;
}
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tools-nginx-reverse-proxy
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: tools-nginx-reverse-proxy
template:
metadata:
labels:
app: tools-nginx-reverse-proxy
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: tools-nginx-reverse-proxy-config
---
apiVersion: v1
kind: Service
metadata:
name: tools-nginx-reverse-proxy
namespace: default
spec:
selector:
app: tools-nginx-reverse-proxy
ports:
- protocol: TCP
port: 80
targetPort: 80**笔记:**
封面图片(显然)是由 bing ai 创建的。
**有用的资源:**
https://oauth2-proxy.github.io/oauth2-proxy/
https://www.keycloak.org
https://github.com/mogensen/cert-checker
https://github.com/guryanovev/CrystalQuartz