mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-07 22:12:53 +00:00
fix: increase nginx transport security
This commit is contained in:
committed by
Rainer Killinger
parent
5f969c53f6
commit
8fe6a2795f
@@ -4,7 +4,10 @@ ADD . /app
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN apk add --update nginx && \
|
RUN apk update && \
|
||||||
|
apk upgrade && \
|
||||||
|
apk add openssl && \
|
||||||
|
apk add nginx && \
|
||||||
rm -rf /var/cache/apk/* && \
|
rm -rf /var/cache/apk/* && \
|
||||||
mv /app/nginx.conf /etc/nginx/
|
mv /app/nginx.conf /etc/nginx/
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ docker run --rm --net="host" \
|
|||||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
-v <path to *.crt-file>:/etc/nginx/certs/ssl.crt \
|
-v <path to *.crt-file>:/etc/nginx/certs/ssl.crt \
|
||||||
-v <path to *.key-file>:/etc/nginx/certs/ssl.key \
|
-v <path to *.key-file>:/etc/nginx/certs/ssl.key \
|
||||||
|
-v <path to certificate chain (*.crt) file>:/etc/nginx/certs/chain.crt \
|
||||||
|
-v <path to dhparam.pem file>:/etc/nginx/certs/dhparam.pem \
|
||||||
gitlab-registry.tubit.tu-berlin.de/stapps/proxy/master
|
gitlab-registry.tubit.tu-berlin.de/stapps/proxy/master
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ const config: ConfigFile = {
|
|||||||
hiddenRoutes: ['/bulk'],
|
hiddenRoutes: ['/bulk'],
|
||||||
outdatedVersions: ['0\\.8\\.\\d+', '0\\.5\\.\\d+', '0\\.6\\.\\d+', '0\\.7\\.\\d+'],
|
outdatedVersions: ['0\\.8\\.\\d+', '0\\.5\\.\\d+', '0\\.6\\.\\d+', '0\\.7\\.\\d+'],
|
||||||
output: '/etc/nginx/conf.d/default.conf',
|
output: '/etc/nginx/conf.d/default.conf',
|
||||||
sslFiles: ['/etc/nginx/certs/ssl.crt', '/etc/nginx/certs/ssl.key'],
|
sslFilePaths: {
|
||||||
|
certificate: '/etc/nginx/certs/ssl.crt',
|
||||||
|
certificateChain: '/etc/nginx/certs/chain.crt',
|
||||||
|
certificateKey: '/etc/nginx/certs/ssl.key',
|
||||||
|
dhparam: '/etc/nginx/certs/dhparam.pem',
|
||||||
|
},
|
||||||
visibleRoutes: ['/search', '/search/multi', '/', '/availabilityCreativework', '/feedback'],
|
visibleRoutes: ['/search', '/search/multi', '/', '/availabilityCreativework', '/feedback'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ events {
|
|||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
http {
|
http {
|
||||||
include mime.types;
|
include mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
@@ -20,10 +19,8 @@ http {
|
|||||||
|
|
||||||
sendfile on;
|
sendfile on;
|
||||||
#tcp_nopush on;
|
#tcp_nopush on;
|
||||||
|
gzip on;
|
||||||
keepalive_timeout 65;
|
keepalive_timeout 65;
|
||||||
|
|
||||||
gzip on;
|
|
||||||
|
|
||||||
include /etc/nginx/conf.d/*;
|
include /etc/nginx/conf.d/*;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ import {SMTP} from '@openstapps/logger/lib/SMTP';
|
|||||||
// use SMTP as a default monitoring system for logger.error();
|
// use SMTP as a default monitoring system for logger.error();
|
||||||
export const logger = new Logger(SMTP.getInstance());
|
export const logger = new Logger(SMTP.getInstance());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of the file paths of the needed ssl certificates
|
||||||
|
*/
|
||||||
|
export interface SSLFilePaths {
|
||||||
|
certificate: string;
|
||||||
|
certificateChain: string;
|
||||||
|
certificateKey: string;
|
||||||
|
dhparam: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of the config file
|
* A representation of the config file
|
||||||
*/
|
*/
|
||||||
@@ -27,7 +37,7 @@ export interface ConfigFile {
|
|||||||
hiddenRoutes: string[];
|
hiddenRoutes: string[];
|
||||||
outdatedVersions: string[];
|
outdatedVersions: string[];
|
||||||
output: string;
|
output: string;
|
||||||
sslFiles: string[];
|
sslFilePaths: SSLFilePaths;
|
||||||
visibleRoutes: string[];
|
visibleRoutes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,3 +51,27 @@ export interface TemplateView {
|
|||||||
staticRoute: string;
|
staticRoute: string;
|
||||||
visibleRoutes: string;
|
visibleRoutes: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nginx protocol parameters to harden serverside settings
|
||||||
|
*/
|
||||||
|
export const protocolHardeningParameters: string = `
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains;";
|
||||||
|
add_header X-Frame-Options DENY;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";`;
|
||||||
|
|
||||||
|
// tslint:disable:max-line-length
|
||||||
|
/**
|
||||||
|
* Nginx ssl parameters to harden serverside settings
|
||||||
|
*/
|
||||||
|
export const sslHardeningParameters: string = `
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
ssl_ecdh_curve X25519:secp384r1;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
ssl_stapling on;
|
||||||
|
ssl_stapling_verify on;`;
|
||||||
|
|||||||
33
src/main.ts
33
src/main.ts
@@ -18,7 +18,14 @@ import * as Dockerode from 'dockerode';
|
|||||||
import {existsSync, readFile} from 'fs-extra';
|
import {existsSync, readFile} from 'fs-extra';
|
||||||
import {render} from 'mustache';
|
import {render} from 'mustache';
|
||||||
import {join} from 'path';
|
import {join} from 'path';
|
||||||
import {ConfigFile, logger, TemplateView} from './common';
|
import {
|
||||||
|
ConfigFile,
|
||||||
|
logger,
|
||||||
|
protocolHardeningParameters,
|
||||||
|
SSLFilePaths,
|
||||||
|
sslHardeningParameters,
|
||||||
|
TemplateView,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
const configFile: ConfigFile = config.util.toObject();
|
const configFile: ConfigFile = config.util.toObject();
|
||||||
|
|
||||||
@@ -123,7 +130,7 @@ export function generateUpstreamMap(
|
|||||||
* @param sslFiles
|
* @param sslFiles
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function generateListener(sslFiles: string[]) {
|
function generateListener(sslFilePaths: SSLFilePaths) {
|
||||||
|
|
||||||
function isSSLCert(path: string) {
|
function isSSLCert(path: string) {
|
||||||
return existsSync(path) && /.*\.crt$/.test(path);
|
return existsSync(path) && /.*\.crt$/.test(path);
|
||||||
@@ -133,17 +140,31 @@ function generateListener(sslFiles: string[]) {
|
|||||||
return existsSync(path) && /.*\.key$/.test(path);
|
return existsSync(path) && /.*\.key$/.test(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPEMFile(path: string) {
|
||||||
|
return existsSync(path) && /.*\.pem$/.test(path);
|
||||||
|
}
|
||||||
|
|
||||||
let listener = '';
|
let listener = '';
|
||||||
|
|
||||||
if (Array.isArray(sslFiles) && sslFiles.length === 2 && sslFiles.some(isSSLCert) && sslFiles.some(isSSLKey)) {
|
if (typeof sslFilePaths !== 'undefined' &&
|
||||||
|
typeof sslFilePaths.certificate === 'string' && isSSLCert(sslFilePaths.certificate) &&
|
||||||
|
typeof sslFilePaths.certificateChain === 'string' && isSSLCert(sslFilePaths.certificate) &&
|
||||||
|
typeof sslFilePaths.certificateKey === 'string' && isSSLKey(sslFilePaths.certificate) &&
|
||||||
|
typeof sslFilePaths.dhparam === 'string' && isPEMFile(sslFilePaths.dhparam)
|
||||||
|
) {
|
||||||
// https listener
|
// https listener
|
||||||
listener = 'listen 443 ssl default_server;\n' +
|
listener = 'listen 443 ssl default_server;\n' +
|
||||||
`ssl_certificate ${sslFiles.find(isSSLCert)};\n` +
|
`ssl_certificate ${sslFilePaths.certificate};\n` +
|
||||||
`ssl_certificate_key ${sslFiles.find(isSSLKey)};\n`;
|
`ssl_certificate_key ${sslFilePaths.certificateKey};\n` +
|
||||||
|
`ssl_trusted_certificate ${sslFilePaths.certificateChain};\n` +
|
||||||
|
`ssl_dhparam ${sslFilePaths.dhparam};\n` +
|
||||||
|
`${sslHardeningParameters}`;
|
||||||
} else {
|
} else {
|
||||||
// default http listener
|
// default http listener
|
||||||
listener = 'listen 80 default_server;';
|
listener = 'listen 80 default_server;';
|
||||||
|
logger.warn('Https usage is not setup properly, falling back to http!');
|
||||||
}
|
}
|
||||||
|
listener = `${listener}\n${protocolHardeningParameters}\n`;
|
||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +204,7 @@ export async function getTemplateView(containers: Dockerode.ContainerInfo[]): Pr
|
|||||||
return {
|
return {
|
||||||
dockerVersionMap: generateUpstreamMap(configFile.activeVersions, configFile.outdatedVersions, containers),
|
dockerVersionMap: generateUpstreamMap(configFile.activeVersions, configFile.outdatedVersions, containers),
|
||||||
hiddenRoutes: (await Promise.all(hiddenRoutesPromises)).join(''),
|
hiddenRoutes: (await Promise.all(hiddenRoutesPromises)).join(''),
|
||||||
listener: generateListener(configFile.sslFiles),
|
listener: generateListener(configFile.sslFilePaths),
|
||||||
staticRoute: await renderTemplate(join('fixtures', 'staticRoute.template'), {cors}),
|
staticRoute: await renderTemplate(join('fixtures', 'staticRoute.template'), {cors}),
|
||||||
visibleRoutes: (await Promise.all(visibleRoutesPromises)).join(''),
|
visibleRoutes: (await Promise.all(visibleRoutesPromises)).join(''),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user