在 Openshift 上保护基于路径的路由
Securing path based routing on Openshift
我在 openshift 上部署的应用程序有 url 作为 https://host:port/app/v1/hello/
我使用 ServiceAccount 作为 Oauth 客户端并且提供者是 Openshift,所以我应该被重定向到 Openshift 登录页面进行授权。
我们已经配置好 openshift/oauth-proxy,效果很好。
https://github.com/openshift/oauth-proxy/
现在我们进一步要求基于路径的路由,例如如果 URL 有 /app/v1 则重定向到 Service1,如果 /app/v2 则重定向到 Service2
这是我的配置的工作示例,
`kind: Template
apiVersion: v1
metadata:
name: deployment-template
objects:
- apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
annotations:
serviceaccounts.openshift.io/oauth-redirectreference.first: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"my-route"}}'
- apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
service.alpha.openshift.io/serving-cert-secret-name: proxy-tls
spec:
selector:
app: spring-boot-docker-openshift-hello-world
ports:
- name: api
protocol: TCP
port: 443 #Port the service listens on.
targetPort: 8443 #Port on the backing pods to which the service forwards connections.
- apiVersion: v1
kind: Route
metadata:
name: my-route
spec:
port:
targetPort: api
path: "/"
to:
kind: Service
name: my-service
tls:
termination: Reencrypt
- apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
labels:
app: spring-boot-docker-openshift-hello-world
version: 0.0.1-SNAPSHOT.1.dev
name: spring-boot-docker-openshift-hello-world
spec:
replicas: 1
selector:
app: spring-boot-docker-openshift-hello-world
strategy:
rollingParams:
timeoutSeconds: 3600
type: Rolling
template:
metadata:
labels:
app: spring-boot-docker-openshift-hello-world
version: 0.0.1-SNAPSHOT.1.dev
spec:
serviceAccount: my-service-account
serviceAccountName: my-service-account
containers:
- name: spring-boot-docker-openshift-hello-world
env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: pokarjm/spring-boot-docker-openshift-hello-world:0.0.1-SNAPSHOT.1.dev
imagePullPolicy: IfNotPresent
securityContext:
privileged: false
ports:
- containerPort: 8080
protocol: TCP
- name: oauth-proxy
image: openshift/oauth-proxy:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8443
name: public
args:
- --https-address=:8443
- --provider=openshift
- --openshift-service-account=my-service-account
- --upstream=http://localhost:8080
- --tls-cert=/etc/tls/private/tls.crt
- --tls-key=/etc/tls/private/tls.key
- --cookie-secret-file=/etc/proxy/secret/session_secret
- --openshift-ca=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- --openshift-sar={"namespace":"spring-boot-docker-openshift-hello-world","resource":"services","name":"my-service","verb":"get"}
- --request-logging=true
volumeMounts:
- mountPath: /etc/tls/private
name: proxy-tls
readOnly: true
- mountPath: /etc/proxy/secret
name: oauth-proxy-secret
readOnly: true
volumes:
- name: proxy-tls
secret:
defaultMode: 420
secretName: proxy-tls
- name: oauth-proxy-secret
secret:
defaultMode: 420
secretName: oauth-proxy-secret
triggers:
- type: ConfigChange
`
现在支持基于路径的路由,即将请求 /app/v1 映射到 Service1,我只是在路由中添加了路径,如下所示,
- apiVersion: v1
kind: Route
metadata:
name: my-route
spec:
port:
targetPort: api
path: "/app/v1"
to:
kind: Service
name: my-service
tls:
termination: Reencrypt
但是通过这些更改,我可以看到如下所示的初始登录页面
但是在点击上面的按钮而不是获取 openshift 登录页面后,我看到了下面,
如果我将路由中的路径更改为路径:“/”,它会工作并显示登录屏幕。
感谢在 openshift/oauth-proxy.
中修复基于路径的路由的任何帮助
尝试将类似 --proxy-prefix=/app/v1
的内容添加到您的 oauth 代理容器。
例如:
[...]
args:
- --https-address=:8443
- --provider=openshift
- --proxy-prefix=/app/v1
- --openshift-service-account=my-service-account
[...]
否则,oauth-proxy 会假定它所服务的应用程序位于您的路由的根目录,从而破坏登录回调重定向。
现在,关于您在评论中提出的问题,我不确定我自己是否完全理解,我没有 OpenShift 集群来测试它,...请稍加保留,欢迎编辑,如果有人能答对的话。
据我了解和回忆:
- 客户端连接到您的应用程序,通过您的oauth-proxy。
- 代理发现您的客户端未经身份验证,并使用其客户端 ID 和密码(已设置
openshift-service-account
,从 /var/run/secrets/kubernetes.io/serviceaccount/
中读取它们)从 Oauth 门户请求令牌。如果检测以某种方式不起作用,您可以改用 client-id=system:serviceaccount:$ns:$sa
和 client-secret-file=/var/run/secrets/kubernetes.io/serviceaccount/token
。
- Oauth SP 使用
serviceaccounts.openshift.io/oauth-redirectreference
annotation (though there's another way to do this, with OauthClient 检查我们的 ServiceAccount,我不太熟悉)匹配客户端请求的应用程序 URL。匹配成功后,SP 回复 oauth-proxy 一些临时令牌
- 知道该令牌和
proxy-prefix
,oauth-proxy 将未经身份验证的用户重定向到 Oauth 登录门户,使用一些编码回调 URL 作为 GET 参数
- 用户登录 OpenShift 用户群
- 成功登录后,Oauth 门户会将您重定向到 oauth-proxy,使用它从您的代理
收到的回调 URL
- oauth-proxy 赎回其代币
- 如果定义了
openshift-sar
,oauth-proxy 会进行一些额外的检查以确保客户端已获得授权,否则任何用户都可以登录
- 用户可以选择同意授予某些权限
在 OpenShift 上下文中,初始令牌请求是使用 login-url
参数完成的,该参数默认为 kubernetes.default.svc/oauth/authorize
,但在某些情况下(不确定是否记得,一些不寻常的网络策略),您可能想强制使用您的 OpenShift 控制台 FQDN。
代币赎回是通过 redeem-url
完成的,默认为 kubernetes.default.svc/oauth/token
。同样,如果 SDN 拒绝此流量,您可以在此处使用 public 控制台 FQDN。
So,proxy-prefix 是如何出现的:只需要 oauth-proxy 构建正确的回调 URL,因为将您送回应用程序的正确 sub-path 的登录表单。
并且 OAuthRedirectReference 主要由 OpenShift 使用,以确保请求令牌的客户端确实是针对给定路由的经过身份验证的客户端。在你的情况下,只匹配一个 FQDN,虽然我认为除了 serviceaccounts.openshift.io/oauth-redirectreference.$name: {"kind": ...}
,你也可以设置像 serviceaccounts.openshift.io/oauth-redirecturi.name: my-path
我在 openshift 上部署的应用程序有 url 作为 https://host:port/app/v1/hello/ 我使用 ServiceAccount 作为 Oauth 客户端并且提供者是 Openshift,所以我应该被重定向到 Openshift 登录页面进行授权。
我们已经配置好 openshift/oauth-proxy,效果很好。 https://github.com/openshift/oauth-proxy/
现在我们进一步要求基于路径的路由,例如如果 URL 有 /app/v1 则重定向到 Service1,如果 /app/v2 则重定向到 Service2
这是我的配置的工作示例,
`kind: Template
apiVersion: v1
metadata:
name: deployment-template
objects:
- apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
annotations:
serviceaccounts.openshift.io/oauth-redirectreference.first: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"my-route"}}'
- apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
service.alpha.openshift.io/serving-cert-secret-name: proxy-tls
spec:
selector:
app: spring-boot-docker-openshift-hello-world
ports:
- name: api
protocol: TCP
port: 443 #Port the service listens on.
targetPort: 8443 #Port on the backing pods to which the service forwards connections.
- apiVersion: v1
kind: Route
metadata:
name: my-route
spec:
port:
targetPort: api
path: "/"
to:
kind: Service
name: my-service
tls:
termination: Reencrypt
- apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
labels:
app: spring-boot-docker-openshift-hello-world
version: 0.0.1-SNAPSHOT.1.dev
name: spring-boot-docker-openshift-hello-world
spec:
replicas: 1
selector:
app: spring-boot-docker-openshift-hello-world
strategy:
rollingParams:
timeoutSeconds: 3600
type: Rolling
template:
metadata:
labels:
app: spring-boot-docker-openshift-hello-world
version: 0.0.1-SNAPSHOT.1.dev
spec:
serviceAccount: my-service-account
serviceAccountName: my-service-account
containers:
- name: spring-boot-docker-openshift-hello-world
env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: pokarjm/spring-boot-docker-openshift-hello-world:0.0.1-SNAPSHOT.1.dev
imagePullPolicy: IfNotPresent
securityContext:
privileged: false
ports:
- containerPort: 8080
protocol: TCP
- name: oauth-proxy
image: openshift/oauth-proxy:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8443
name: public
args:
- --https-address=:8443
- --provider=openshift
- --openshift-service-account=my-service-account
- --upstream=http://localhost:8080
- --tls-cert=/etc/tls/private/tls.crt
- --tls-key=/etc/tls/private/tls.key
- --cookie-secret-file=/etc/proxy/secret/session_secret
- --openshift-ca=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- --openshift-sar={"namespace":"spring-boot-docker-openshift-hello-world","resource":"services","name":"my-service","verb":"get"}
- --request-logging=true
volumeMounts:
- mountPath: /etc/tls/private
name: proxy-tls
readOnly: true
- mountPath: /etc/proxy/secret
name: oauth-proxy-secret
readOnly: true
volumes:
- name: proxy-tls
secret:
defaultMode: 420
secretName: proxy-tls
- name: oauth-proxy-secret
secret:
defaultMode: 420
secretName: oauth-proxy-secret
triggers:
- type: ConfigChange
`
现在支持基于路径的路由,即将请求 /app/v1 映射到 Service1,我只是在路由中添加了路径,如下所示,
- apiVersion: v1
kind: Route
metadata:
name: my-route
spec:
port:
targetPort: api
path: "/app/v1"
to:
kind: Service
name: my-service
tls:
termination: Reencrypt
但是通过这些更改,我可以看到如下所示的初始登录页面
但是在点击上面的按钮而不是获取 openshift 登录页面后,我看到了下面,
如果我将路由中的路径更改为路径:“/”,它会工作并显示登录屏幕。 感谢在 openshift/oauth-proxy.
中修复基于路径的路由的任何帮助尝试将类似 --proxy-prefix=/app/v1
的内容添加到您的 oauth 代理容器。
例如:
[...]
args:
- --https-address=:8443
- --provider=openshift
- --proxy-prefix=/app/v1
- --openshift-service-account=my-service-account
[...]
否则,oauth-proxy 会假定它所服务的应用程序位于您的路由的根目录,从而破坏登录回调重定向。
现在,关于您在评论中提出的问题,我不确定我自己是否完全理解,我没有 OpenShift 集群来测试它,...请稍加保留,欢迎编辑,如果有人能答对的话。
据我了解和回忆:
- 客户端连接到您的应用程序,通过您的oauth-proxy。
- 代理发现您的客户端未经身份验证,并使用其客户端 ID 和密码(已设置
openshift-service-account
,从/var/run/secrets/kubernetes.io/serviceaccount/
中读取它们)从 Oauth 门户请求令牌。如果检测以某种方式不起作用,您可以改用client-id=system:serviceaccount:$ns:$sa
和client-secret-file=/var/run/secrets/kubernetes.io/serviceaccount/token
。 - Oauth SP 使用
serviceaccounts.openshift.io/oauth-redirectreference
annotation (though there's another way to do this, with OauthClient 检查我们的 ServiceAccount,我不太熟悉)匹配客户端请求的应用程序 URL。匹配成功后,SP 回复 oauth-proxy 一些临时令牌 - 知道该令牌和
proxy-prefix
,oauth-proxy 将未经身份验证的用户重定向到 Oauth 登录门户,使用一些编码回调 URL 作为 GET 参数 - 用户登录 OpenShift 用户群
- 成功登录后,Oauth 门户会将您重定向到 oauth-proxy,使用它从您的代理 收到的回调 URL
- oauth-proxy 赎回其代币
- 如果定义了
openshift-sar
,oauth-proxy 会进行一些额外的检查以确保客户端已获得授权,否则任何用户都可以登录 - 用户可以选择同意授予某些权限
在 OpenShift 上下文中,初始令牌请求是使用 login-url
参数完成的,该参数默认为 kubernetes.default.svc/oauth/authorize
,但在某些情况下(不确定是否记得,一些不寻常的网络策略),您可能想强制使用您的 OpenShift 控制台 FQDN。
代币赎回是通过 redeem-url
完成的,默认为 kubernetes.default.svc/oauth/token
。同样,如果 SDN 拒绝此流量,您可以在此处使用 public 控制台 FQDN。
So,proxy-prefix 是如何出现的:只需要 oauth-proxy 构建正确的回调 URL,因为将您送回应用程序的正确 sub-path 的登录表单。
并且 OAuthRedirectReference 主要由 OpenShift 使用,以确保请求令牌的客户端确实是针对给定路由的经过身份验证的客户端。在你的情况下,只匹配一个 FQDN,虽然我认为除了 serviceaccounts.openshift.io/oauth-redirectreference.$name: {"kind": ...}
,你也可以设置像 serviceaccounts.openshift.io/oauth-redirecturi.name: my-path