production

This commit is contained in:
anhefti 2019-08-29 11:46:54 +02:00
parent 431063ab32
commit 956df03cc1
9 changed files with 120 additions and 41 deletions

View file

@ -0,0 +1 @@
/secrets

View file

@ -1,41 +1,36 @@
spring.profiles.include=prod-ws,prod-gui
file.encoding=UTF-8
logging.level.org.apache.tomcat.util.net.NioEndpoint=DEBUG
logging.level.ch=DEBUG
sebserver.certs.password=[SET_PWD]
sebserver.mariadb.password=[SET_PWD]
sebserver.password=[SET_PWD]
server.address=0.0.0.0
server.port=443
server.servlet.context-path=/
##########################################################
### Security
security.require-ssl=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=file:/certs/seb-server-keystore.pkcs12
server.ssl.key-store=C:/dev/workspaces/sebserver/seb-server/docker/prod/standalone/selfsigned/certs/seb-server-keystore.pkcs12
server.ssl.key-store-password=${sebserver.certs.password}
server.ssl.key-alias=sebserver
server.ssl.key-password=${sebserver.certs.password}
server.ssl.trust-store=file:/certs/seb-server-truststore.pkcs12
server.ssl.trust-store=C:/dev/workspaces/sebserver/seb-server/docker/prod/standalone/selfsigned/certs/seb-server-truststore.pkcs12
server.ssl.trust-store-password=${sebserver.certs.password}
server.ssl.enabled-protocols=SSLv3,TLSv1,TLSv1.1,TLSv1.2
server.ssl.enabled-protocols=TLSv1,TLSv1.1,TLSv1.2
javax.net.ssl.keyStore=/certs/seb-server-keystore.pkcs12
javax.net.ssl.keyStorePassword=${sebserver.certs.password}
javax.net.ssl.trustStore=/certs/seb-server-truststore.pkcs12
javax.net.ssl.trustStorePassword=${sebserver.certs.password}
##########################################################
### SEB Server Overall
sebserver.webservice.api.admin.clientSecret=${sebserver.password}
sebserver.webservice.internalSecret=${sebserver.password}
# Default logging level in the form "logging.level" + namespace=LEVEL
logging.level.ch=DEBUG
logging.file=log/sebserver.log
# If webservice or gui runs on ssl and this flag is true, an integrated redirect from http to https is activated
# Disable this if a redirect is done by a pre-processing proxy
sebserver.ssl.redirect.enabled=true
##########################################################
### SEB Server Webservice configuration
# logging
logging.file=log/sebserver.log
# database server
datastore.mariadb.server.address=seb-server-mariadb
datastore.mariadb.server.port=3306
@ -53,9 +48,11 @@ spring.datasource.hikari.maxLifetime=1800000
spring.datasource.password=${sebserver.mariadb.password}
# webservice configuration
sebserver.webservice.api.admin.clientSecret=${sebserver.password}
sebserver.webservice.internalSecret=${sebserver.password}
sebserver.webservice.distributed=false
sebserver.webservice.http.scheme=https
sebserver.webservice.http.server.name=0.0.0.0
sebserver.webservice.http.server.name=${server.address}
sebserver.webservice.http.redirect.gui=/gui
sebserver.webservice.api.admin.clientId=guiClient
sebserver.webservice.api.admin.endpoint=/admin-api/v1
@ -75,8 +72,6 @@ sebserver.webservice.lms.openedx.api.token.request.paths=/oauth2/access_token
management.endpoints.web.base-path=/actuator
management.endpoints.web.exposure.include=logfile,loggers
##########################################################
### SEB Server GUI configuration
server.servlet.session.cookie.http-only=true
@ -84,11 +79,12 @@ server.servlet.session.tracking-modes=cookie
sebserver.gui.entrypoint=/gui
sebserver.gui.webservice.protocol=https
sebserver.gui.webservice.address=0.0.0.0
sebserver.gui.webservice.address=localhost
sebserver.gui.webservice.port=443
sebserver.gui.webservice.apipath=/admin-api/v1
# defines the polling interval that is used to poll the webservice for client connection data on a monitored exam page
sebserver.gui.webservice.poll-interval=500
sebserver.gui.webservice.mock-lms-enabled=true
sebserver.gui.theme=css/sebserver.css

View file

@ -2,26 +2,28 @@ FROM openjdk:11-jre-stretch
RUN apt-get update && apt-get install -y openssl
ENV KEYSTORE_PWD=
ENV OPENSSL_SUBJ="/C=CH/ST=Zuerich/L=Zuerich"
ENV OPENSSL_CA="${OPENSSL_SUBJ}/CN=SEB_SEVER_CN"
VOLUME /certs
WORKDIR /certs
RUN export $(grep -v '^#' secrets | xargs)
CMD openssl genrsa -out ca-key.pem 2048 \
&& openssl req -new -x509 -key ca-key.pem -nodes -days 3600 -subj "${OPENSSL_CA}" -out ca.pem \
&& openssl req -newkey rsa:2048 -days 3600 -nodes -config /certs/config/certs.cnf -keyout server-key.pem -out server-req.pem \
&& openssl req -newkey rsa:2048 -days 3600 -nodes -config certs.cnf -keyout server-key.pem -out server-req.pem \
&& openssl rsa -in server-key.pem -out server-key.pem \
&& openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem \
&& openssl req -newkey rsa:2048 -days 3600 -nodes -config /certs/config/certs.cnf -keyout client-key.pem -out client-req.pem \
&& openssl req -newkey rsa:2048 -days 3600 -nodes -config certs.cnf -keyout client-key.pem -out client-req.pem \
&& openssl rsa -in client-key.pem -out client-key.pem \
&& openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem \
&& openssl verify -CAfile ca.pem server-cert.pem client-cert.pem \
&& openssl x509 -in ca.pem -inform pem -out ca.der -outform der \
&& openssl pkcs12 -export -out client-cert.pkcs12 -in client-cert.pem -inkey client-key.pem -passout pass:"${KEYSTORE_PWD}" \
&& keytool -importkeystore -destkeystore seb-server-keystore.pkcs12 -deststorepass "${KEYSTORE_PWD}" -srckeystore client-cert.pkcs12 -srcstoretype PKCS12 -srcstorepass "${KEYSTORE_PWD}" \
&& keytool -import -file ca.pem -keystore seb-server-truststore.pkcs12 -storepass "${KEYSTORE_PWD}" -srcstoretype PKCS12 -noprompt \
&& keytool -genkeypair -alias sebserver -dname "CN=localhost, OU=ETHZ, O=ETHZ, L=Zuerich, S=Zuerich, C=CH" -keyalg RSA -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore seb-server-keystore.pkcs12 -storepass "${KEYSTORE_PWD}" -validity 3650 \
&& keytool -export -alias sebserver -keystore seb-server-keystore.pkcs12 -rfc -file sebserver.cert -storetype PKCS12 -storepass "${KEYSTORE_PWD}" -noprompt \
&& keytool -importcert -trustcacerts -alias sebserver -file sebserver.cert -keystore seb-server-truststore.pkcs12 -storetype PKCS12 -storepass "${KEYSTORE_PWD}" -noprompt
&& keytool -importcert -trustcacerts -alias sebserver -file sebserver.cert -keystore seb-server-truststore.pkcs12 -storetype PKCS12 -storepass "${KEYSTORE_PWD}" -noprompt \
&& keytool -import -alias mariadb-ca -file ca.pem -keystore seb-server-truststore.pkcs12 -storepass "${KEYSTORE_PWD}" -srcstoretype PKCS12 -noprompt \
&& keytool -import -alias mariadb-client -file client-cert.pem -keystore seb-server-truststore.pkcs12 -storepass "${KEYSTORE_PWD}" -srcstoretype PKCS12 -noprompt \
&& keytool -import -alias mariadb-server -file server-cert.pem -keystore seb-server-keystore.pkcs12 -storepass "${KEYSTORE_PWD}" -srcstoretype PKCS12 -noprompt \

View file

@ -7,11 +7,11 @@ services:
container_name: gencerts
volumes:
- ./certs:/certs
- .:/certs/config
- ./certs.cnf:/certs/certs.cnf
- ./secrets:/certs/secrets
environment:
- SERVER_CN=seb-server-mariadb
- CLIENT_CN=seb-server-mariadb
- KEYSTORE_PWD=[SET_PWD]
mariadb:
image: "mariadb/server:10.3"
@ -20,8 +20,8 @@ services:
- .:/etc/mysql/conf.d
- ./certs:/etc/mysql/certs
- seb-server-mariadb-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=[SET_PWD]
env_file:
- secrets
ports:
- 3306:3306
networks:

View file

@ -25,6 +25,15 @@ ENV SEBSERVER_VERSION=${SEBSERVER_VERSION}
WORKDIR /sebserver
COPY --from=1 /sebserver/target/seb-server-"$SEBSERVER_VERSION".jar /sebserver
ENTRYPOINT exec java -Djavax.net.debug=SSL -jar seb-server-"${SEBSERVER_VERSION}".jar --spring.profiles.active=prod --spring.config.location=file:/config/,classpath:/config/
RUN export $(grep -v '^#' secrets | xargs)
ENTRYPOINT exec java \
-Djavax.net.debug=SSL \
-jar seb-server-"${SEBSERVER_VERSION}".jar \
--spring.profiles.active=prod \
--spring.config.location=file:/config/,classpath:/config/ \
--sebserver.certs.password="${KEYSTORE_PWD}" \
--sebserver.mariadb.password="${MYSQL_ROOT_PASSWORD}" \
--sebserver.password="${SEBSERVER_PWD}" \
EXPOSE 443

View file

@ -8,10 +8,24 @@
package ch.ethz.seb.sebserver;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.profile.ProdGuiProfile;
import ch.ethz.seb.sebserver.gbl.profile.ProdWebServiceProfile;
/** SEB-Server (Safe Exam Browser Server) is a server component to maintain and support
* Exams running with SEB (Safe Exam Browser). TODO add link(s)
@ -25,9 +39,7 @@ import org.springframework.cache.annotation.EnableCaching;
* SEB-Server uses Spring's profiles to consequently separate sub-components of the webservice
* and GUI and can be used to start the components on separate servers or within the same
* server instance. Additional to the usual profiles like dev, prod, test there are combining
* profiles like dev-ws, dev-gui and prod-ws, prod-gui
*
* TODO documentation for presets to start all-in-one server or separated gui- and webservice- server */
* profiles like dev-ws, dev-gui and prod-ws, prod-gui */
@SpringBootApplication(exclude = {
UserDetailsServiceAutoConfiguration.class,
})
@ -39,4 +51,53 @@ public class SEBServer {
SpringApplication.run(SEBServer.class, args);
}
/*
* Add an additional redirect Connector on http port to redirect all http calls
* to https.
*
* NOTE: This works with TomcatServletWebServerFactory and embedded tomcat.
* If the webservice and/or gui is going to running on another server or
* redirect is handled by a proxy, this redirect can be deactivated within
* the "sebserver.ssl.redirect.enabled" property set to false
*/
@Bean
@ProdWebServiceProfile
@ProdGuiProfile
public ServletWebServerFactory servletContainer(
final Environment env,
final ApplicationContext applicationContext) {
final String enabled = env.getProperty(
"sebserver.ssl.redirect.enabled",
Constants.FALSE_STRING);
if (!BooleanUtils.toBoolean(enabled)) {
return new TomcatServletWebServerFactory();
}
final TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(final Context context) {
final SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
final SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(redirectConnector(env));
return tomcat;
}
private Connector redirectConnector(final Environment env) {
final String sslPort = env.getRequiredProperty("server.port");
final Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(80);
connector.setSecure(false);
connector.setRedirectPort(Integer.valueOf(sslPort));
return connector;
}
}

View file

@ -154,7 +154,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
log.info("Initialize with secure ClientHttpRequestFactory for production");
final String truststoreFilePath = env
.getProperty("javax.net.ssl.trustStore", "");
.getProperty("server.ssl.trust-store", "");
if (StringUtils.isBlank(truststoreFilePath)) {
throw new IllegalArgumentException("Missing trust-store file path");
@ -163,7 +163,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
final File trustStoreFile = ResourceUtils.getFile("file:" + truststoreFilePath);
final char[] password = env
.getProperty("javax.net.ssl.trustStorePassword", "")
.getProperty("server.ssl.trust-store-password", "")
.toCharArray();
if (password.length < 3) {
@ -171,6 +171,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
throw new IllegalArgumentException("Missing or incorrect trust-store password");
}
// Set the specified trust-store also on javax.net.ssl level
System.setProperty("javax.net.ssl.trustStore", truststoreFilePath);
System.setProperty("javax.net.ssl.trustStorePassword", String.valueOf(password));
final SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(trustStoreFile, password)

View file

@ -22,6 +22,7 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@ -98,15 +99,18 @@ public class ResourceService {
private final I18nSupport i18nSupport;
private final RestService restService;
private final CurrentUser currentUser;
private final boolean mock_lms_enabled;
protected ResourceService(
final I18nSupport i18nSupport,
final RestService restService,
final CurrentUser currentUser) {
final CurrentUser currentUser,
@Value("${sebserver.gui.webservice.mock-lms-enabled:true}") final boolean mock_lms_enabled) {
this.i18nSupport = i18nSupport;
this.restService = restService;
this.currentUser = currentUser;
this.mock_lms_enabled = mock_lms_enabled;
}
public I18nSupport getI18nSupport() {
@ -137,6 +141,7 @@ public class ResourceService {
public List<Tuple<String>> lmsTypeResources() {
return Arrays.asList(LmsType.values())
.stream()
.filter(lmsType -> lmsType != LmsType.MOCKUP || this.mock_lms_enabled)
.map(lmsType -> new Tuple<>(
lmsType.name(),
this.i18nSupport.getText(LMSSETUP_TYPE_PREFIX + lmsType.name(), lmsType.name())))

View file

@ -12,6 +12,7 @@ sebserver.gui.webservice.port=8080
sebserver.gui.webservice.apipath=/admin-api/v1
# defines the polling interval that is used to poll the webservice for client connection data on a monitored exam page
sebserver.gui.webservice.poll-interval=500
sebserver.gui.webservice.mock-lms-enabled=true
sebserver.gui.theme=css/sebserver.css