Zuul服务端有三种模式,分别是
- HTTP
- HTTP/2(需要TLS)
- HTTP - Mutual TLS
目前除了这三种模式,有新增了支持的模式为WEBSOCKET和SSE
根据Zuul提供的示例源代码可知:
@Singleton
public class SampleServerStartup extends BaseServerStartup {
enum ServerType {
HTTP,
HTTP2,
HTTP_MUTUAL_TLS,
WEBSOCKET,
SSE
}
private static final String[] WWW_PROTOCOLS = new String[]{"TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"};
private static final ServerType SERVER_TYPE = ServerType.HTTP;
private final PushConnectionRegistry pushConnectionRegistry;
private final SamplePushMessageSenderInitializer pushSenderInitializer;
@Inject
public SampleServerStartup(ServerStatusManager serverStatusManager, FilterLoader filterLoader,
SessionContextDecorator sessionCtxDecorator, FilterUsageNotifier usageNotifier,
RequestCompleteHandler reqCompleteHandler, Registry registry,
DirectMemoryMonitor directMemoryMonitor, EventLoopGroupMetrics eventLoopGroupMetrics,
EurekaClient discoveryClient, ApplicationInfoManager applicationInfoManager,
AccessLogPublisher accessLogPublisher, PushConnectionRegistry pushConnectionRegistry,
SamplePushMessageSenderInitializer pushSenderInitializer) {
super(serverStatusManager, filterLoader, sessionCtxDecorator, usageNotifier, reqCompleteHandler, registry,
directMemoryMonitor, eventLoopGroupMetrics, discoveryClient, applicationInfoManager,
accessLogPublisher);
this.pushConnectionRegistry = pushConnectionRegistry;
this.pushSenderInitializer = pushSenderInitializer;
}
@Override
protected Map<Integer, ChannelInitializer> choosePortsAndChannels(
ChannelGroup clientChannels,
ChannelConfig channelDependencies) {
Map<Integer, ChannelInitializer> portsToChannels = new HashMap<>();
int port = new DynamicIntProperty("zuul.server.port.main", 7001).get();
ChannelConfig channelConfig = BaseServerStartup.defaultChannelConfig();
int pushPort = new DynamicIntProperty("zuul.server.port.http.push", 7008).get();
ServerSslConfig sslConfig;
/* These settings may need to be tweaked depending if you're running behind an ELB HTTP listener, TCP listener,
* or directly on the internet.
*/
switch (SERVER_TYPE) {
/* The below settings can be used when running behind an ELB HTTP listener that terminates SSL for you
* and passes XFF headers.
*/
case HTTP:
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.ALWAYS);
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, false);
channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false);
channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, false);
portsToChannels.put(port, new ZuulServerChannelInitializer(port, channelConfig, channelDependencies, clientChannels));
logPortConfigured(port, null);
break;
/* The below settings can be used when running behind an ELB TCP listener with proxy protocol, terminating
* SSL in Zuul.
*/
case HTTP2:
sslConfig = ServerSslConfig.withDefaultCiphers(
loadFromResources("server.cert"),
loadFromResources("server.key"),
WWW_PROTOCOLS);
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);
channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false);
channelConfig.set(CommonChannelConfigKeys.serverSslConfig, sslConfig);
channelConfig.set(CommonChannelConfigKeys.sslContextFactory, new BaseSslContextFactory(registry, sslConfig));
addHttp2DefaultConfig(channelConfig);
portsToChannels.put(port, new Http2SslChannelInitializer(port, channelConfig, channelDependencies, clientChannels));
logPortConfigured(port, sslConfig);
break;
/* The below settings can be used when running behind an ELB TCP listener with proxy protocol, terminating
* SSL in Zuul.
*
* Can be tested using certs in resources directory:
* curl https://localhost:7001/test -vk --cert src/main/resources/ssl/client.cert:zuul123 --key src/main/resources/ssl/client.key
*/
case HTTP_MUTUAL_TLS:
sslConfig = new ServerSslConfig(
WWW_PROTOCOLS,
ServerSslConfig.getDefaultCiphers(),
loadFromResources("server.cert"),
loadFromResources("server.key"),
null,
ClientAuth.REQUIRE,
loadFromResources("truststore.jks"),
loadFromResources("truststore.key"),
false);
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);
channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false);
channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, true);
channelConfig.set(CommonChannelConfigKeys.serverSslConfig, sslConfig);
channelConfig.set(CommonChannelConfigKeys.sslContextFactory, new BaseSslContextFactory(registry, sslConfig));
portsToChannels.put(port, new Http1MutualSslChannelInitializer(port, channelConfig, channelDependencies, clientChannels));
logPortConfigured(port, sslConfig);
break;
/* Settings to be used when running behind an ELB TCP listener with proxy protocol as a Push notification
* server using WebSockets */
case WEBSOCKET:
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);
channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false);
channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, true);
channelDependencies.set(ZuulDependencyKeys.pushConnectionRegistry, pushConnectionRegistry);
portsToChannels.put(port, new SampleWebSocketPushChannelInitializer(port, channelConfig, channelDependencies, clientChannels));
logPortConfigured(port, null);
// port to accept push message from the backend, should be accessible on internal network only.
portsToChannels.put(pushPort, pushSenderInitializer);
logPortConfigured(pushPort, null);
break;
/* Settings to be used when running behind an ELB TCP listener with proxy protocol as a Push notification
* server using Server Sent Events (SSE) */
case SSE:
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);
channelConfig.set(CommonChannelConfigKeys.preferProxyProtocolForClientIp, true);
channelConfig.set(CommonChannelConfigKeys.isSSlFromIntermediary, false);
channelConfig.set(CommonChannelConfigKeys.withProxyProtocol, true);
channelDependencies.set(ZuulDependencyKeys.pushConnectionRegistry, pushConnectionRegistry);
portsToChannels.put(port, new SampleSSEPushChannelInitializer(port, channelConfig, channelDependencies, clientChannels));
logPortConfigured(port, null);
// port to accept push message from the backend, should be accessible on internal network only.
portsToChannels.put(pushPort, pushSenderInitializer);
logPortConfigured(pushPort, null);
break;
}
return portsToChannels;
}
private File loadFromResources(String s) {
return new File(ClassLoader.getSystemResource("ssl/" + s).getFile());
}
}
HTTP
当运行在ELB HTTP监听器之后时使用该种模式,可以重视TLS并且传递XFF头给后端。
如果运行时在明文模式下并且没有任何的ELB,那么由于安全原因你很有可能希望去除代理头,可以如下配置
channelConfig.set(CommonChannelConfigKeys.allowProxyHeadersWhen, StripUntrustedProxyHeadersHandler.AllowWhen.NEVER);
HTTP/2
ELB不支持HTTP/2,所以你如果要使用HTTP/2,你很可能要使用ELB TCP监听器并且在Zuul上终止该协议。HTTP/2协议配置需要SSL证书,开启代理协议来替换XFF头
如果使用ALB来终止HTTP/2,则可以使用HTTP模式
Mutual TLS
ELB也不支持Mutual TLS(双方认证,双方都配备证书),所以你不得不使用ELB TCP监听器来在Zuul上终止TLS。在这种模式中,你需要一个TLS证书和来自客户证书的信任存储。你很可能希望开启代理协议来替换XFF头。
WEBSOCKET
当使用代理协议运行在ELB TCP监听器之后并且使用WebSockets作为推送消息的服务端时使用该配置。
SSE
当使用代理协议运行在ELB TCP监听器之后使用服务器发送事件(server sent events)作为消息发送服务器时使用该种模式
- ELB 亚马逊AWS的负载均衡 Elastic Load Balancing
- ALB 亚马逊AWS新推出的负载均衡 Application Load Balancer
- SSE 服务器发送事件 server sent events
网友评论