21
21
package eu .openanalytics .containerproxy ;
22
22
23
23
import com .fasterxml .jackson .datatype .jsr353 .JSR353Module ;
24
+ import eu .openanalytics .containerproxy .backend .ContainerBackendFactory ;
25
+ import eu .openanalytics .containerproxy .backend .docker .DockerEngineBackend ;
26
+ import eu .openanalytics .containerproxy .backend .docker .DockerSwarmBackend ;
27
+ import eu .openanalytics .containerproxy .backend .kubernetes .KubernetesBackend ;
24
28
import eu .openanalytics .containerproxy .service .hearbeat .ActiveProxiesService ;
25
29
import eu .openanalytics .containerproxy .service .hearbeat .HeartbeatService ;
26
- import eu .openanalytics .containerproxy .service .hearbeat .SessionReActivatorService ;
30
+ import eu .openanalytics .containerproxy .service .hearbeat .IHeartbeatProcessor ;
31
+ import eu .openanalytics .containerproxy .util .LoggingConfigurer ;
27
32
import eu .openanalytics .containerproxy .util .ProxyMappingManager ;
28
33
import io .undertow .Handlers ;
29
34
import io .undertow .server .handlers .SameSiteCookieHandler ;
38
43
import org .springframework .boot .actuate .health .HealthIndicator ;
39
44
import org .springframework .boot .actuate .redis .RedisHealthIndicator ;
40
45
import org .springframework .boot .autoconfigure .SpringBootApplication ;
46
+ import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
41
47
import org .springframework .boot .autoconfigure .condition .ConditionalOnProperty ;
48
+ import org .springframework .boot .autoconfigure .security .servlet .UserDetailsServiceAutoConfiguration ;
42
49
import org .springframework .boot .web .embedded .undertow .UndertowServletWebServerFactory ;
43
50
import org .springframework .boot .web .server .PortInUseException ;
44
51
import org .springframework .boot .web .servlet .FilterRegistrationBean ;
47
54
import org .springframework .core .env .Environment ;
48
55
import org .springframework .data .redis .connection .RedisConnectionFactory ;
49
56
import org .springframework .scheduling .annotation .EnableAsync ;
57
+ import org .springframework .scheduling .annotation .EnableScheduling ;
50
58
import org .springframework .scheduling .concurrent .ThreadPoolTaskExecutor ;
51
59
import org .springframework .security .core .session .SessionRegistry ;
52
60
import org .springframework .security .web .session .HttpSessionEventPublisher ;
53
61
import org .springframework .session .FindByIndexNameSessionRepository ;
54
62
import org .springframework .session .Session ;
55
- import org .springframework .session .web .http .DefaultCookieSerializer ;
56
63
import org .springframework .session .security .SpringSessionBackedSessionRegistry ;
64
+ import org .springframework .session .web .http .DefaultCookieSerializer ;
57
65
import org .springframework .web .filter .FormContentFilter ;
58
66
59
67
import javax .annotation .PostConstruct ;
63
71
import java .nio .file .Files ;
64
72
import java .nio .file .Paths ;
65
73
import java .security .Security ;
66
- import java .util .Arrays ;
74
+ import java .util .List ;
67
75
import java .util .Objects ;
68
76
import java .util .Properties ;
69
77
import java .util .concurrent .Executor ;
70
78
79
+ import static eu .openanalytics .containerproxy .api .ApiSecurityService .PROP_API_SECURITY_HIDE_SPEC_DETAILS ;
80
+ import static eu .openanalytics .containerproxy .service .ProxyService .PROPERTY_STOP_PROXIES_ON_SHUTDOWN ;
81
+
82
+ @ EnableScheduling
71
83
@ EnableAsync
72
- @ SpringBootApplication
84
+ @ SpringBootApplication ( exclude = { UserDetailsServiceAutoConfiguration . class })
73
85
@ ComponentScan ("eu.openanalytics" )
74
86
public class ContainerProxyApplication {
75
87
public static final String CONFIG_FILENAME = "application.yml" ;
@@ -94,10 +106,18 @@ public class ContainerProxyApplication {
94
106
public static Boolean secureCookiesEnabled ;
95
107
public static String sameSiteCookiePolicy ;
96
108
97
- public static void main ( String [] args ) {
109
+ static {
98
110
Security .addProvider (new BouncyCastleProvider ());
111
+ ContainerBackendFactory .addBackend ("docker" , DockerEngineBackend .class );
112
+ ContainerBackendFactory .addBackend ("docker-swarm" , DockerSwarmBackend .class );
113
+ ContainerBackendFactory .addBackend ("kubernetes" , KubernetesBackend .class );
114
+ }
115
+
116
+ public static void main (String [] args ) {
99
117
SpringApplication app = new SpringApplication (ContainerProxyApplication .class );
100
118
119
+ app .addListeners (new LoggingConfigurer ());
120
+
101
121
boolean hasExternalConfig = Files .exists (Paths .get (CONFIG_FILENAME ));
102
122
if (!hasExternalConfig ) app .setAdditionalProfiles (CONFIG_DEMO_PROFILE );
103
123
@@ -131,6 +151,26 @@ public void init() {
131
151
if (sameSiteCookiePolicy .equalsIgnoreCase ("none" ) && !secureCookiesEnabled ) {
132
152
log .warn ("WARNING: Invalid configuration detected: same-site-cookie policy is set to None, but secure-cookies are not enabled. Secure cookies must be enabled when using None as same-site-cookie policy " );
133
153
}
154
+
155
+
156
+ if (environment .getProperty ("proxy.store-mode" , "" ).equalsIgnoreCase ("Redis" )) {
157
+ if (!environment .getProperty ("spring.session.store-type" , "" ).equalsIgnoreCase ("redis" )) {
158
+ // running in HA mode, but not using Redis sessions
159
+ log .warn ("WARNING: Invalid configuration detected: store-mode is set to Redis (i.e. High-Availability mode), but you are not using Redis for user sessions!" );
160
+ }
161
+ if (environment .getProperty (PROPERTY_STOP_PROXIES_ON_SHUTDOWN , Boolean .class , true )) {
162
+ // running in HA mode, but proxies are removed when shutting down
163
+ log .warn ("WARNING: Invalid configuration detected: store-mode is set to Redis (i.e. High-Availability mode), but proxies are stopped at shutdown of server!" );
164
+ }
165
+ }
166
+
167
+ boolean hideSpecDetails = environment .getProperty (PROP_API_SECURITY_HIDE_SPEC_DETAILS , Boolean .class , true );
168
+ if (!hideSpecDetails ) {
169
+ log .warn ("WARNING: Insecure configuration detected: The API is configured to return the full spec of proxies, " +
170
+ "this may contain sensitive values such as the container image, secret environment variables etc. " +
171
+ "Remove the proxy.api-security.hide-spec-details property to enable API security." );
172
+ }
173
+
134
174
}
135
175
136
176
@ Autowired (required = false )
@@ -213,7 +253,7 @@ public Health health() {
213
253
@ Bean
214
254
@ ConditionalOnProperty (name = "spring.session.store-type" , havingValue = "redis" )
215
255
public <S extends Session > SessionRegistry sessionRegistry (FindByIndexNameSessionRepository <S > sessionRepository ) {
216
- return new SpringSessionBackedSessionRegistry <S >(sessionRepository );
256
+ return new SpringSessionBackedSessionRegistry <>(sessionRepository );
217
257
}
218
258
219
259
@ Bean
@@ -231,8 +271,14 @@ public Executor taskExecutor() {
231
271
}
232
272
233
273
@ Bean
234
- public HeartbeatService heartbeatService (ActiveProxiesService activeProxiesService , SessionReActivatorService sessionReActivatorService ) {
235
- return new HeartbeatService (Arrays .asList (activeProxiesService , sessionReActivatorService ));
274
+ public HeartbeatService heartbeatService (List <IHeartbeatProcessor > heartbeatProcessors ) {
275
+ return new HeartbeatService (heartbeatProcessors );
276
+ }
277
+
278
+ @ Bean
279
+ @ ConditionalOnMissingBean
280
+ public ActiveProxiesService activeProxiesService () {
281
+ return new ActiveProxiesService ();
236
282
}
237
283
238
284
public static Properties getDefaultProperties () {
@@ -249,6 +295,7 @@ public static Properties getDefaultProperties() {
249
295
250
296
// disable logging of requests, since this reads part of the requests and therefore undertow is unable to correctly handle those requests
251
297
properties .put ("logging.level.org.springframework.web.servlet.DispatcherServlet" , "INFO" );
298
+ properties .put ("logging.level.io.fabric8.kubernetes.client.dsl.internal.VersionUsageUtils" , "ERROR" );
252
299
253
300
properties .put ("spring.application.name" , "ContainerProxy" );
254
301
@@ -263,8 +310,9 @@ public static Properties getDefaultProperties() {
263
310
properties .put ("management.server.port" , "9090" );
264
311
// enable prometheus endpoint by default (but not the exporter)
265
312
properties .put ("management.endpoint.prometheus.enabled" , "true" );
313
+ properties .put ("management.endpoint.recyclable.enabled" , "true" );
266
314
// include prometheus and health endpoint in exposure
267
- properties .put ("management.endpoints.web.exposure.include" , "health,prometheus" );
315
+ properties .put ("management.endpoints.web.exposure.include" , "health,prometheus,recyclable " );
268
316
269
317
// ====================
270
318
@@ -284,6 +332,10 @@ public static Properties getDefaultProperties() {
284
332
285
333
properties .put ("spring.config.use-legacy-processing" , true );
286
334
335
+ // disable openapi docs and swagger ui
336
+ properties .put ("springdoc.api-docs.enabled" , false );
337
+ properties .put ("springdoc.swagger-ui.enabled" , false );
338
+
287
339
return properties ;
288
340
}
289
341
@@ -293,4 +345,4 @@ private static void setDefaultProperties(SpringApplication app) {
293
345
System .setProperty ("jdk.serialSetFilterAfterRead" , "true" );
294
346
}
295
347
296
- }
348
+ }
0 commit comments