Ingress Nginx Configuration-Snippet 故障排查与解决方案

问题描述

当您在 Ingress Nginx 中使用 configuration-snippet 注解时,可能会遇到以下错误:

1
2
3
Error from server (BadRequest): error when creating "ingress-nginx-proxy-complete.yaml": 
admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: 
annotation group ConfigurationSnippet contains risky annotation based on ingress configuration

原因分析

这个错误是由于 Ingress Nginx 的安全验证机制导致的。从 Ingress Nginx Controller v1.9.0 开始,引入了更严格的安全验证,会阻止包含潜在风险配置的注解。

被阻止的配置包括:

  1. location 块配置:如 location ~* \.(blob|manifest)$ { ... }
  2. 复杂的重写规则:可能包含恶意代码
  3. 不安全的头设置:可能被用于注入攻击
  4. 文件路径操作:如日志文件路径

解决方案

方案1:使用安全的标准注解(推荐)

使用 Ingress Nginx 提供的标准注解替代 configuration-snippet

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: docker-hub-proxy-safe
  annotations:
    # 使用 proxy-set-headers 替代 configuration-snippet
    nginx.ingress.kubernetes.io/proxy-set-headers: "default/proxy-set-headers"
    
    # 使用 custom-headers 替代 add_header
    nginx.ingress.kubernetes.io/custom-headers: "default/custom-headers"
    
    # 标准代理配置
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    
    # 缓冲区配置
    nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
    nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
    nginx.ingress.kubernetes.io/proxy-max-temp-file-size: "1024m"
    nginx.ingress.kubernetes.io/proxy-request-buffering: "off"

对应的 ConfigMap:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: ConfigMap
metadata:
  name: proxy-set-headers
  namespace: default
data:
  # 设置 Host 头
  Host: "registry-1.docker.io"
  # Docker Registry API 版本
  Docker-Distribution-Api-Version: "registry/2.0"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: custom-headers
  namespace: default
data:
  # 安全头
  X-Content-Type-Options: "nosniff"
  X-Frame-Options: "DENY"
  X-XSS-Protection: "1; mode=block"

方案2:使用 ConfigMap 全局配置

修改 Ingress Nginx Controller 的 ConfigMap 来应用全局配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
data:
  # 全局代理配置
  proxy-connect-timeout: "600"
  proxy-send-timeout: "600"
  proxy-read-timeout: "600"
  proxy-buffer-size: "16k"
  proxy-buffers-number: "8"
  proxy-max-temp-file-size: "1024m"
  proxy-body-size: "0"
  
  # 全局头配置
  add-headers: "ingress-nginx/custom-headers"
  proxy-set-headers: "ingress-nginx/proxy-set-headers"
  
  # 启用压缩
  use-gzip: "true"
  gzip-level: "6"
  gzip-min-length: "1024"

方案3:禁用安全验证(不推荐)

如果您确实需要使用 configuration-snippet,可以禁用安全验证,但这会降低安全性:

1
2
# 编辑 Ingress Nginx Controller 的部署
kubectl edit deployment ingress-nginx-controller -n ingress-nginx

在容器参数中添加:

1
2
3
4
5
args:
  - /nginx-ingress-controller
  - --enable-annotation-validation=false  # 禁用安全验证
  - --configmap=$(POD_NAMESPACE)/nginx-configuration
  - --annotations-prefix=nginx.ingress.kubernetes.io

⚠️ 警告:禁用安全验证会使您的集群面临安全风险,不建议在生产环境中使用。

验证配置

1. 检查 Ingress 状态

1
2
3
4
5
# 查看 Ingress 状态
kubectl get ingress docker-hub-proxy-safe

# 查看详细事件
kubectl describe ingress docker-hub-proxy-safe

2. 测试代理功能

1
2
3
4
5
# 测试 Docker Hub 代理
docker pull dockerhub.yourdomain.com/library/nginx:latest

# 查看 Nginx 日志
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep dockerhub

3. 检查配置是否生效

1
2
3
4
5
# 进入 Ingress Controller Pod
kubectl exec -n ingress-nginx deployment/ingress-nginx-controller -- cat /etc/nginx/nginx.conf | grep -A 10 -B 10 dockerhub

# 检查 Nginx 配置是否正确
kubectl exec -n ingress-nginx deployment/ingress-nginx-controller -- nginx -t

最佳实践

1. 使用安全的替代方案

原始配置安全替代方案
configuration-snippet 中的 add_headernginx.ingress.kubernetes.io/custom-headers
configuration-snippet 中的 proxy_set_headernginx.ingress.kubernetes.io/proxy-set-headers
configuration-snippet 中的 location使用多个 Ingress 规则
configuration-snippet 中的重写规则nginx.ingress.kubernetes.io/rewrite-target

2. 配置示例对比

❌ 不安全的配置:

1
2
3
4
5
6
7
annotations:
  nginx.ingress.kubernetes.io/configuration-snippet: |
    location ~* \.(blob|manifest|config)$ {
      proxy_cache_valid 200 302 10m;
      add_header X-Cache-Status $upstream_cache_status;
    }
    add_header X-Content-Type-Options nosniff;

✅ 安全的配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
annotations:
  nginx.ingress.kubernetes.io/proxy-set-headers: "default/proxy-headers"
  nginx.ingress.kubernetes.io/custom-headers: "default/custom-headers"
  nginx.ingress.kubernetes.io/proxy-buffering: "on"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: custom-headers
  namespace: default
data:
  X-Content-Type-Options: "nosniff"
  X-Frame-Options: "DENY"

3. 监控和告警

设置监控来跟踪代理性能和错误:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: v1
kind: ServiceMonitor
metadata:
  name: ingress-nginx-registry-proxy
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/component: controller
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

常见问题

Q1: 为什么我的配置被阻止了?

A: Ingress Nginx 的安全验证机制检测到您的配置包含潜在风险。这是为了保护您的集群安全。

Q2: 如何知道哪些配置是安全的?

A: 参考 Ingress Nginx 官方文档中的安全注解列表

Q3: 我可以在测试环境中禁用安全验证吗?

A: 技术上可以,但不推荐。更好的做法是找到安全的替代方案。

Q4: 配置更改后没有生效?

A: 检查以下几点:

  1. ConfigMap 是否在正确的命名空间
  2. Ingress Controller 是否重启以加载新配置
  3. 使用 kubectl describe ingress 查看事件

Q5: 如何调试配置问题?

A: 使用以下命令:

1
2
3
4
5
6
7
8
# 查看 Nginx 配置
kubectl exec -n ingress-nginx deployment/ingress-nginx-controller -- cat /etc/nginx/nginx.conf

# 测试配置
kubectl exec -n ingress-nginx deployment/ingress-nginx-controller -- nginx -t

# 查看日志
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller

总结

使用 configuration-snippet 被拒绝时,应该:

  1. 首选方案:使用标准注解和 ConfigMap 替代
  2. 次选方案:通过 ConfigMap 进行全局配置
  3. 避免:禁用安全验证

这样既能保证功能实现,又能维护集群的安全性。

0%