【发布时间】:2020-07-02 20:53:48
【问题描述】:
我已经在 ingress 命名空间中通过 helm 安装了 Nginx Ingress Controller。
helm ls --namespace ingress
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
nginx-ingress ingress 1 2020-03-15 10:47:51.143159 +0530 IST deployed nginx-ingress-1.34.2 0.30.0
服务和部署如下
apiVersion: v1
kind: Service
metadata:
name: test-service
labels:
app.kubernetes.io/name: test-service
helm.sh/chart: test-service-0.1.0
app.kubernetes.io/instance: test-service
app.kubernetes.io/managed-by: Helm
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: '"true"'
spec:
type: LoadBalancer
ports:
- port: 8080
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: test-service
app.kubernetes.io/instance: test-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-service
labels:
app.kubernetes.io/name: test-service
helm.sh/chart: test-service-0.1.0
app.kubernetes.io/instance: test-service
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: test-service
app.kubernetes.io/instance: test-service
template:
metadata:
labels:
app.kubernetes.io/name: test-service
app.kubernetes.io/instance: test-service
spec:
containers:
- name: test-service
image: "<acr-url>/test-service:c93c58c0bd4918de06d46381a89b293087262cf9"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /devops/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
httpGet:
path: /devops/health/readiness
port: 8080
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
env:
- name: test-serviceClientId
valueFrom:
secretKeyRef:
key: test-serviceClientId
name: test-service-133
- name: test-serviceClientSecret
valueFrom:
secretKeyRef:
key: test-serviceClientSecret
name: test-service-133
- name: test-serviceTenantClientId
valueFrom:
secretKeyRef:
key: test-serviceTenantClientId
name: test-service-133
- name: test-serviceTenantClientSecret
valueFrom:
secretKeyRef:
key: test-serviceTenantClientSecret
name: test-service-133
resources:
limits:
cpu: 800m
requests:
cpu: 300m
使用重写配置服务的入口,如下所示
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-service
labels:
app.kubernetes.io/name: test-service
helm.sh/chart: test-service-0.1.0
app.kubernetes.io/instance: test-service
app.kubernetes.io/managed-by: Helm
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- apiexample.centralus.cloudapp.azure.com
secretName: tls-secret
rules:
- host: "apiexample.centralus.cloudapp.azure.com"
http:
paths:
- path: /testservice(/|$)(.*)
backend:
serviceName: test-service
servicePort: 8080
tls-secret 已使用
生成$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=apiexample.centralus.cloudapp.azure.com/O=apiexample.centralus.cloudapp.azure.com"
$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt
在入口应用 tls 配置之前,我能够从 api 端点获得响应。 api 端点由 oauth 保护。
API 端点:
http://apiexample.centralus.cloudapp.azure.com/testservice/tenant/api/v1/endpoint
在入口应用 TLS 配置并点击
https://apiexample.centralus.cloudapp.azure.com/testservice/tenant/api/v1/endpoint
我得到默认后端 404。
我已经使用另一个示例服务(不受 oauth 保护)测试了带有入口的 TLS,它似乎适用于该服务。 这是其他服务的配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: tea
spec:
replicas: 3
selector:
matchLabels:
app: tea
template:
metadata:
labels:
app: tea
spec:
containers:
- name: tea
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: tea-svc
labels:
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: tea
服务的入口配置如下
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- apiexample.centralus.cloudapp.azure.com
secretName: tls-secret
rules:
- host: apiexample.centralus.cloudapp.azure.com
http:
paths:
- path: /teaprefix(/|$)(.*)
backend:
serviceName: tea-svc
servicePort: 80
端点
https://apiexample.centralus.cloudapp.azure.com/teaprefix/someurl
工作正常。
如果我的配置中缺少任何内容以及我可能忽略的任何潜在问题,请告诉我。
注意:Service 和 Ingress 部署在 default 命名空间中,Ingress Controller 运行在 ingress 命名空间中 Nginx Ingress Controller 在 2 个 Pod 中运行
带有 TLS 配置的 Ingress Controller 的日志
Pod1
10.244.0.1 - - [22/Mar/2020:06:57:12 +0000] "GET /testservice/tenant/api/v1/endpoint HTTP/1.1" 302 0 "-" "PostmanRuntime/7.23.0" 1495 0.004 [default-test-service-8080] [] 10.244.0.7:8080 0 0.004 302 f4671ede2f95148220c21fe44de6fdad
10.244.0.1 - - [22/Mar/2020:06:57:13 +0000] "GET /tenant/api/v1/endpoint HTTP/1.1" 404 21 "http://apiexample.centralus.cloudapp.azure.com/tenant/api/v1/endpoint" "PostmanRuntime/7.23.0" 1563 0.001 [upstream-default-backend] [] 10.244.0.225:8080 21 0.004 404 ed41b36bc6b89b60bc3f208539a0d44c
Pod2
10.244.0.1 - - [22/Mar/2020:06:57:12 +0000] "GET /tenant/api/v1/endpoint HTTP/1.1" 308 171 "https://apiexample.centralus.cloudapp.azure.com/testservice/tenant/api/v1/endpoint" "PostmanRuntime/7.23.0" 1580 0.000 [upstream-default-backend] [] - - - - ce955b7bb5118169e99dd4051060c897
来自没有 TLS 配置的 Ingress Controller 的日志
10.244.0.1 - - [22/Mar/2020:07:04:34 +0000] "GET /testservice/tenant/api/v1/endpoint HTTP/1.1" 200 276 "-" "PostmanRuntime/7.23.0" 1495 2.165 [default-test-service-8080] [] 10.244.0.4:8080 548 2.168 200 e866f277def90c398df4e509e45718b2
更新
在后端服务 (test-service) 上禁用身份验证也会导致相同的行为。 在不应用 TLS 的情况下,无需任何承载令牌即可使用 http 访问端点。 应用 TLS 后,当我使用 https/http 访问端点时,获取默认后端 - 404
更新
在没有
的情况下通过 ClusterIP 公开服务service.beta.kubernetes.io/azure-load-balancer-internal: '"true"'
注释而不是 LoadBalancer 似乎也没有帮助。端点在没有 TLS 且应用 TLS 的情况下工作,获取默认后端 - 404
更新
测试服务是具有以下 WebSecurityConfiguration 的 Spring Boot 应用程序
@Component
@EnableResourceServer
public class WebSecurityConfiguration extends ResourceServerConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSecurityConfiguration.class);
private final HealthCheckWebSecurity healthCheckWebSecurity = new HealthCheckWebSecurity();
private final Oauth2Settings oauth2Settings;
private final JwtTokenStore jwtTokenStore;
private final TenantService tenantService;
private final TransportGuaranteeWebSecurity transportGuaranteeWebSecurity;
@Autowired
public WebSecurityConfiguration(
Oauth2Settings oauth2Settings,
JwtTokenStore jwtTokenStore,
TenantService tenantService,
TransportGuaranteeWebSecurity transportGuaranteeWebSecurity) {
this.oauth2Settings = oauth2Settings;
this.jwtTokenStore = jwtTokenStore;
this.tenantService = tenantService;
this.transportGuaranteeWebSecurity = transportGuaranteeWebSecurity;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
String resourceId = oauth2Settings.getResource("default").getResourceId();
LOGGER.info("Resource service id: {}", resourceId);
resources.resourceId(resourceId).tokenStore(jwtTokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().anyRequest();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.csrf().disable();
healthCheckWebSecurity.configure(http);
transportGuaranteeWebSecurity.configure(http);
http.authorizeRequests().anyRequest().permitAll();
http.addFilterAfter(buildTenancyContextFilter(), ChannelProcessingFilter.class);
http.addFilterAfter(buildLongUrlFilter(), ChannelProcessingFilter.class);
}
private TenancyContextFilter buildTenancyContextFilter() {
return new TenancyContextFilter(tenantService,
new PathVariableTenantExtractor(Arrays.asList("/{tenantAlias}/api/**")));
}
private LongRequestHttpFilter buildLongUrlFilter() {
return new LongRequestHttpFilter();
}
}
public final class TransportGuaranteeWebSecurity {
private TransportGuaranteeSettings transportGuaranteeSettings;
TransportGuaranteeWebSecurity(TransportGuaranteeSettings transportGuaranteeSettings) {
this.transportGuaranteeSettings = transportGuaranteeSettings;
}
public void configure(HttpSecurity httpSecurity) throws Exception {
if (httpsRequired()) {
httpSecurity.requiresChannel().anyRequest().requiresSecure();
} else {
httpSecurity.requiresChannel().anyRequest().requiresInsecure();
}
}
private boolean httpsRequired() {
final String transportGuarantee = transportGuaranteeSettings.getTransportGuarantee();
return !TransportGuaranteeSettings.TRANSPORT_GUARANTEE_NONE.equalsIgnoreCase(transportGuarantee);
}
}
@ConfigurationProperties(prefix = "web.security")
public class TransportGuaranteeSettings {
static final String TRANSPORT_GUARANTEE_NONE = "NONE";
static final String TRANSPORT_GUARANTEE_CONFIDENTIAL = "CONFIDENTIAL";
private static final Logger LOGGER = LoggerFactory.getLogger(TransportGuaranteeSettings.class);
private static final String TRANSPORT_GUARANTEE_PROPERTY = "web.security.transportGuarantee";
private String transportGuarantee;
public String getTransportGuarantee() {
return transportGuarantee;
}
public void setTransportGuarantee(String transportGuarantee) {
this.transportGuarantee = transportGuarantee.trim();
logUnexpectedValue();
}
private void logUnexpectedValue() {
if (!TRANSPORT_GUARANTEE_NONE.equalsIgnoreCase(transportGuarantee)
&& !TRANSPORT_GUARANTEE_CONFIDENTIAL.equalsIgnoreCase(transportGuarantee)) {
LOGGER.debug(
"Unknown value '{}' for property '{}' (expected '{}' or '{}'). Defaulted to '{}'.",
transportGuarantee, TRANSPORT_GUARANTEE_PROPERTY, TRANSPORT_GUARANTEE_NONE, TRANSPORT_GUARANTEE_CONFIDENTIAL,
TRANSPORT_GUARANTEE_CONFIDENTIAL);
}
}
}
在我的 application.yaml 中,
web.security.transportGuarantee: NONE
租户上下文过滤器从 URL 中提取租户信息并设置一个 ThreadLocal。这应该没有任何问题,因为我可以在没有 TLS 配置的情况下访问端点。出于同样的原因,我也没有看到 TransportGuaranteeWebSecurity 有任何问题。
更多调试日志
kubectl 获取 pods -owide --namespace ingress
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ingress-controller-5fcbccd545-bdh25 1/1 Running 1 15d 10.244.0.22 aks-agentpool-44086776-vmss000000 <none> <none>
nginx-ingress-controller-5fcbccd545-ptx6j 1/1 Running 0 15d 10.244.0.21 aks-agentpool-44086776-vmss000000 <none> <none>
nginx-ingress-default-backend-554d7bd77c-zxzlf 1/1 Running 0 15d 10.244.0.225 aks-agentpool-44086776-vmss000000 <none> <none>
kubectl 获取 svc
test-service LoadBalancer 10.0.231.35 13.89.111.39 8080:31534/TCP 14d
tea-svc ClusterIP 10.0.12.216 <none> 80/TCP 17d
kubectl 获取
test-service apiexample.centralus.cloudapp.azure.com 10.240.0.4 80, 443 15d
【问题讨论】:
-
提供来自 nginx 入口控制器 pod 的日志
-
@Arghya Sadhu 在帖子中添加了日志
-
您说使用 TLS 测试了另一个服务并且它有效,因为您对两个入口使用相同的证书,那么两个后端服务之间的主要区别是什么?您提到了 OAUTH,也许这就是 link 帮助。
-
@KoopaKiller 我已禁用身份验证并尝试过。但是看到同样的行为。我已经用详细信息更新了票证。
-
@java_geek,在您的主要服务中,您正在使用
service.beta.kubernetes.io/azure-load-balancer-internal: '"true"'的注释,而在您的测试服务中则没有。我不确定是否会干扰某些事情。我将尝试使用 GCP 而不是 Azure 来重现您的场景,然后返回这里结果。
标签: nginx kubernetes kubernetes-ingress nginx-ingress azure-aks