Kubernetes集群中如何验证Pod1收到的HTTP请求是否来自Pod2
解决方案
方案1:自定义私有请求头+IP双重校验(推荐,安全性最高)
可避免IP伪造或者CIDR配置错误导致的校验失效:
- 首先在
Pod2的PHP Symfony服务调用Pod1的代码中,添加自定义私有请求头X-Internal-Service-Token,值为仅两个服务知晓的随机密钥,建议将该密钥存入K8s Secret,两个Pod都通过环境变量挂载读取,不要硬编码在代码中。 - 其次在
Ingress网关层配置规则,直接清空所有外部请求携带的X-Internal-Service-Token头,避免外部用户伪造该头冒充内部请求。 - 最后在
Pod1的Express服务中,同时校验请求是否携带正确的X-Internal-Service-Token,且来源IP属于K8s集群内部Pod CIDR段,两项都符合即可判定为来自Pod2的内部请求。
方案2:基于K8s内部IP白名单校验
如果不想修改Symfony服务的请求逻辑,可直接校验请求的真实来源IP:
- K8s集群内部Pod之间直接通信时,
req.socket.remoteAddress会返回请求发起方的真实Pod IP,不会被Ingress修改。 - 你可以将
Pod2的固定IP段、或者Pod2对应的Service ClusterIP加入白名单,匹配到白名单IP的请求即可判定为来自Pod2的内部请求。 - 若Pod2会动态扩缩容导致IP变化,可通过K8s API动态拉取Pod2的实时IP列表更新白名单。
和express-rate-limit的集成示例
你可以通过自定义keyGenerator或者skip参数,实现内部请求和外部请求的差异化限流:
const rateLimit = require('express-rate-limit'); const RedisStore = require('rate-limit-redis'); const { createClient } = require('redis'); const redisClient = createClient({ // 你的Redis连接配置 }); redisClient.connect().catch(console.error); // 从环境变量读取配置,环境变量来自K8s Secret挂载 const INTERNAL_TOKEN = process.env.INTERNAL_SERVICE_TOKEN; const POD2_IP_PREFIX = process.env.POD2_CIDR_PREFIX || '10.244.2.'; // 替换为你的Pod2所属CIDR前缀 const apiLimiter = rateLimit({ store: new RedisStore({ sendCommand: (...args) => redisClient.sendCommand(args), }), // 跳过内部请求的限流,也可以自定义限流阈值 skip: (req) => { const tokenValid = req.headers['x-internal-service-token'] === INTERNAL_TOKEN; const ipValid = req.socket.remoteAddress.startsWith(POD2_IP_PREFIX); return tokenValid && ipValid; }, // 外部请求使用x-forwarded-for的公网IP作为限流key keyGenerator: (req) => { return req.headers['x-forwarded-for'] || req.socket.remoteAddress; }, // 外部请求限流规则:15分钟最多100次请求,可自行调整 windowMs: 15 * 60 * 1000, max: 100, standardHeaders: true, legacyHeaders: false, }); // 挂载限流中间件 app.use(apiLimiter);
注意事项
- 不要完全依赖
x-forwarded-for头判断请求来源,该头可以被外部用户伪造,必须结合私有请求头或者真实来源IP校验。 - 私有请求头一定要在Ingress层配置丢弃外部传入的值,避免伪造风险。
- 所有敏感配置(比如内部密钥、CIDR段)都建议通过K8s Secret管理,不要硬编码在代码或者配置文件中。
内容的提问来源于stack exchange,提问作者Rohit Bohara
相关产品推荐
相关产品推荐

