Merge branch 'feature/SEARCH-1885_SSLWebProxyGenerator' into 'master'

Add support for WebProxy with SSL

See merge request search_discovery/insightengine!190
This commit is contained in:
Angel Borroy
2019-10-08 12:30:37 +01:00
13 changed files with 321 additions and 60 deletions
@@ -1,12 +1,7 @@
# generator-alfresco-docker-compose
> Alfresco Docker Compose Generator
This project generates a collection of Docker Compose Templates to test Repository and Search Services/Insight Engine with different configurations:
* Plain HTTP communications
* TLS/SSL Mutual Authentication communications
* Sharding (dynamic) with different Sharding Methods
* Replication (master/slave)
This project generates a collection of Docker Compose Templates to test Repository and Search Services/Insight Engine with different configurations.
## Project structure
@@ -14,7 +9,6 @@ Following templates are provided.
```
$ tree generators/app/templates/
generators/app/templates/
├── 6.1
│   ├── .env
│   ├── docker-compose-ce.yml
@@ -30,6 +24,13 @@ generators/app/templates/
│   │   ├── empty
│   │   ├── sharding-content-model-context.xml
│   │   └── sharding-content-model.xml
│   ├── config
│   │   ├── cert
│   │   │   ├── localhost.cer
│   │   │   └── localhost.key
│   │   └── nginx
│   │   ├── nginx.conf
│   │   └── nginx.htpasswd
│   ├── search
│   │   └── Dockerfile
│   ├── share
@@ -54,6 +55,7 @@ generators/app/templates/
* `share` includes a Dockerfile template to start Share Web Application
* `model` includes a default forms model (Sharding Explicit Routing or empty)
* `search` includes a Dockerfile template to start Search Services and Insight Engine
* `config` includes configuration for HTTP Web Proxy (NGINX)
* `zeppelin` includes a Dockerfile template to start Zeppelin with SSL
* `keystores` includes every truststore and keystore required for SSL configuration
@@ -99,15 +101,21 @@ If you chose ACS 6.1, a prompt will allow you to use AGS.
When using Community, some different options can be combined:
* Plain HTTP (http) or TLS/SSL Mutual Authentication (https)
* Plain HTTP (http) or TLS/SSL Mutual Authentication (https) for communication between Alfresco and SOLR
* Plain HTTP (http) or HTTPs (https) for Http Web Proxy for HTTP access to services
* Protect the access to SOLR REST API in the Http WebProxy to forbid direct access to Alfresco Web Proxy port
* Use SOLR Replication in Master/Slave mode (only when using http)
```
? Would you like to use Alfresco enterprise or community? community
? Would you like to use http or https? http
? Would you like to use a SOLR Replication (2 nodes in master-slave)? Yes
? Would you like to use HTTP or mTLS for Alfresco-SOLR communication? http
? Would you like to use HTTP or HTTPs for Web Proxy? http
? Would you like to protect the access to SOLR REST API? Yes
? Would you like to use a SOLR Replication (2 nodes in master-slave)? No
```
**Note** that when choosing *mTLS* or *HTTPs*, default certificates, truststores and keystores are provided for testing purposes. If you are planning to use this Docker Compose template for real environments, replace these cryptographic stores with another generated by yourself to increase the security of your system.
## Enterprise
When using Enterprise, some options can be added to Community configuration:
@@ -172,22 +180,6 @@ Sample configuration is available in [images/share/model/sharding-share-config-c
If *Sharding* is selected, a default `share-config-custom-dev.xml` file with required forms configuration for Sharding custom model will be available in deployment folder. Add your configuration to this file.
## Configuration catalog
| Version | Comms | Replication | Sharding | Insight | Zeppelin |
| - | - | - | - | - | - |
| community | http | - | x | x | x |
| community | http | true | x | x | x |
| community | https | x | x | x | x |
| enterprise | http | - | - | (*) | (*) |
| enterprise | http | true | false | (*) | (*) |
| enterprise | http | false | true | (*) | (*) |
| enterprise | https | x | - | (*) | (*) |
| enterprise | https | x | true | (*) | (*) |
| enterprise | https | x | true | (*) | (*) |
Both `community` and `enterprise` ACS deployments can be used with the same options, but `enterprise` may also use Insight Engine (replacing Search Services) and Insight Zeppelin services.
## Passing parameters from command line
Default values for options can be specified in the command line, using a `--name=value` pattern. When an options is specified in the command line, the question is not prompted to the user, so you can generate a Docker Compose template with no user interaction.
@@ -202,6 +194,8 @@ $ yo alfresco-docker-compose --acsVersion=6.2 --alfrescoVersion=community --http
`--ags:`: only available when acsVersion=6.1
`--alfrescoVersion`: community or enterprise
`--httpMode`: http or https
`--httpWebMode`: http or https
`--protectSolr`: true or false
`--clustering`: true or false
`--insightEngine`: true or false
`--zeppelin`: true or false
@@ -224,20 +218,24 @@ $ docker-compose down
**Community URLs**
*HTTP*
*WebProxy HTTP and Alfresco-SOLR HTTP*
http://localhost:8080/share
http://localhost:8080/alfresco
http://localhost:8080/solr (with HTTP basic auth)
http://localhost:8083/solr
http://localhost:8080/
When using SOLR Replication, additionally
http://localhost:8084/solr
*SSL*
*WebProxy HTTP and Alfresco-SOLR mTLS*
http://localhost:8080/share
@@ -247,25 +245,57 @@ https://localhost:8443/alfresco
https://localhost:8083/solr
http://localhost:8080/
*WebProxy HTTPs and Alfresco-SOLR HTTP*
https://localhost/share
https://localhost/alfresco
https://localhost/solr (with HTTP basic auth)
https://localhost/
When using SOLR Replication, additionally
http://localhost:8084/solr
*WebProxy HTTPs and Alfresco-SOLR mTLS*
https://localhost/share
https://localhost/alfresco
https://localhost:8083/solr
https://localhost/
**Enterprise URLs**
*HTTP*
*WebProxy HTTP and Alfresco-SOLR HTTP*
http://localhost:8080/share
http://localhost:8080/alfresco
http://localhost:8080/solr (with HTTP basic auth)
http://localhost:8083/solr
http://localhost:9090/zeppelin
http://localhost:8080/
When using SOLR Replication or Sharding, additionally
http://localhost:8084/solr
*SSL*
*WebProxy HTTP and Alfresco-SOLR mTLS*
http://localhost:8080/share
@@ -277,6 +307,34 @@ https://localhost:8083/solr
http://localhost:9090/zeppelin
When using SOLR Sharding, additionally
http://localhost:8080/
https://localhost:8084/solr
*WebProxy HTTPs and Alfresco-SOLR HTTP*
https://localhost/share
https://localhost/alfresco
https://localhost/solr (with HTTP basic auth)
http://localhost:9090/zeppelin
https://localhost/
When using SOLR Replication, additionally
http://localhost:8084/solr
*WebProxy HTTPs and Alfresco-SOLR mTLS*
https://localhost/share
https://localhost/alfresco
https://localhost:8083/solr
http://localhost:9090/zeppelin
https://localhost/
@@ -4,12 +4,8 @@ var banner = require('./banner')
/**
* This module buids a Docker Compose template to test
* Repository and Search Services/Insight Engine in
* different configurations:
* - Plain HTTP communications
* - TLS/SSL Mutual Authentication communications
* - Sharding (dynamic)
* - Replication (master-slave)
* Repository and Search Services/Insight Engine with
* different configurations.
*/
module.exports = class extends Generator {
@@ -45,10 +41,23 @@ module.exports = class extends Generator {
{
type: 'list',
name: 'httpMode',
message: 'Would you like to use http or https?',
message: 'Would you like to use HTTP or mTLS for Alfresco-SOLR communication?',
choices: [ "http", "https" ],
default: 'http'
},
{
type: 'list',
name: 'httpWebMode',
message: 'Would you like to use HTTP or HTTPs for Web Proxy?',
choices: [ "http", "https" ],
default: 'http'
},
{
type: 'confirm',
name: 'protectSolr',
message: 'Would you like to protect the access to SOLR REST API?',
default: 'true'
},
{
whenFunction: response => response.httpMode == 'http',
type: 'confirm',
@@ -186,6 +195,8 @@ module.exports = class extends Generator {
this.destinationPath('docker-compose.yml'),
{
httpMode: this.props.httpMode,
httpWebMode: this.props.httpWebMode,
port: (this.props.httpWebMode == 'http' ? '8080' : '443'),
secureComms: (this.props.httpMode == 'http' ? 'none' : 'https'),
alfrescoPort: (this.props.httpMode == 'http' ? '8080' : '8443'),
replication: (this.props.replication ? "true" : "false"),
@@ -226,7 +237,9 @@ module.exports = class extends Generator {
this.templatePath(imagesDirectory + '/share/Dockerfile'),
this.destinationPath('share/Dockerfile'),
{
shareImage: shareImageName
shareImage: shareImageName,
httpWebMode: this.props.httpWebMode,
port: (this.props.httpWebMode == 'http' ? '8080' : '443'),
}
);
// Copy Sharding Content Forms or an empty file to allow forms deployments
@@ -282,6 +295,24 @@ module.exports = class extends Generator {
}
}
// Copy NGINX Configuration
this.fs.copyTpl(
this.templatePath(imagesDirectory + '/config/nginx'),
this.destinationPath('config'),
{
port: (this.props.httpWebMode == 'http' ? '8080' : '443'),
httpMode: this.props.httpMode,
httpWebMode: this.props.httpWebMode,
protectSolr: (this.props.protectSolr ? 'true' : 'false')
}
);
if (this.props.httpWebMode == 'https') {
this.fs.copy(
this.templatePath(imagesDirectory + '/config/cert'),
this.destinationPath('config/cert')
);
}
}
};
@@ -19,3 +19,4 @@ ACS_NGINX_TAG=3.0.0
ACS_COMMUNITY_NGINX_TAG=1.0.0
SEARCH_TAG=latest
ZEPPELIN_TAG=latest
ACA_TAG=master-latest
@@ -26,8 +26,8 @@ services:
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dshare.host=localhost
-Dalfresco.port=8082
-Daos.baseUrlOverwrite=http://localhost:8082/alfresco/aos
-Dalfresco.port=8080
-Daos.baseUrlOverwrite=http://localhost:8080/alfresco/aos
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
@@ -159,13 +159,28 @@ services:
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
content-app:
image: alfresco/alfresco-content-app:${ACA_TAG}
mem_limit: 256m
depends_on:
- alfresco
# HTTP proxy to provide HTTP Default port access to services
# SOLR API and SOLR Web Console are protected to avoid unauthenticated access
proxy:
image: alfresco/acs-community-ngnix:${ACS_COMMUNITY_NGINX_TAG}
image: nginx:stable-alpine
mem_limit: 128m
depends_on:
- alfresco
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./config/nginx.htpasswd:/etc/nginx/conf.d/nginx.htpasswd <% if (httpWebMode == 'https') { %>
- ./config/cert/localhost.cer:/etc/nginx/localhost.cer
- ./config/cert/localhost.key:/etc/nginx/localhost.key <% } %>
ports:
- 8080:8080
- <%=port%>:<%=port%>
links:
- alfresco
- share
- share
- solr6
- content-app
@@ -301,24 +301,31 @@ services:
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
digital-workspace:
content-app:
image: quay.io/alfresco/alfresco-digital-workspace:${DIGITAL_WORKSPACE_TAG}
mem_limit: 128m
environment:
BASEPATH: ./
# HTTP proxy to provide HTTP Default port access to services
# SOLR API and SOLR Web Console are protected to avoid unauthenticated access
proxy:
image: alfresco/alfresco-acs-nginx:${ACS_NGINX_TAG}
image: nginx:stable-alpine
mem_limit: 128m
depends_on:
- alfresco
- digital-workspace
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./config/nginx.htpasswd:/etc/nginx/conf.d/nginx.htpasswd <% if (httpWebMode == 'https') { %>
- ./config/cert/localhost.cer:/etc/nginx/localhost.cer
- ./config/cert/localhost.key:/etc/nginx/localhost.key <% } %>
ports:
- 8080:8080
- <%=port%>:<%=port%>
links:
- digital-workspace
- alfresco
- share
- solr6
- content-app
volumes:
shared-file-store-volume:
@@ -14,3 +14,4 @@ ACS_NGINX_TAG=3.0.1
ACS_COMMUNITY_NGINX_TAG=1.0.0
SEARCH_TAG=latest
ZEPPELIN_TAG=latest
ACA_TAG=master-latest
@@ -26,8 +26,8 @@ services:
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dshare.host=localhost
-Dalfresco.port=8082
-Daos.baseUrlOverwrite=http://localhost:8082/alfresco/aos
-Dalfresco.port=8080
-Daos.baseUrlOverwrite=http://localhost:8080/alfresco/aos
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
-Ddeployment.method=DOCKER_COMPOSE
@@ -215,13 +215,28 @@ services:
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
content-app:
image: alfresco/alfresco-content-app:${ACA_TAG}
mem_limit: 256m
depends_on:
- alfresco
# HTTP proxy to provide HTTP Default port access to services
# SOLR API and SOLR Web Console are protected to avoid unauthenticated access
proxy:
image: alfresco/acs-community-ngnix:${ACS_COMMUNITY_NGINX_TAG}
image: nginx:stable-alpine
mem_limit: 128m
depends_on:
- alfresco
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./config/nginx.htpasswd:/etc/nginx/conf.d/nginx.htpasswd <% if (httpWebMode == 'https') { %>
- ./config/cert/localhost.cer:/etc/nginx/localhost.cer
- ./config/cert/localhost.key:/etc/nginx/localhost.key <% } %>
ports:
- 8080:8080
- <%=port%>:<%=port%>
links:
- alfresco
- share
- share
- solr6
- content-app
@@ -324,24 +324,31 @@ services:
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
digital-workspace:
content-app:
image: quay.io/alfresco/alfresco-digital-workspace:${DIGITAL_WORKSPACE_TAG}
mem_limit: 128m
environment:
BASEPATH: ./
# HTTP proxy to provide HTTP Default port access to services
# SOLR API and SOLR Web Console are protected to avoid unauthenticated access
proxy:
image: alfresco/alfresco-acs-nginx:${ACS_NGINX_TAG}
image: nginx:stable-alpine
mem_limit: 128m
depends_on:
- alfresco
- digital-workspace
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./config/nginx.htpasswd:/etc/nginx/conf.d/nginx.htpasswd <% if (httpWebMode == 'https') { %>
- ./config/cert/localhost.cer:/etc/nginx/localhost.cer
- ./config/cert/localhost.key:/etc/nginx/localhost.key <% } %>
ports:
- 8080:8080
- <%=port%>:<%=port%>
links:
- digital-workspace
- alfresco
- share
- solr6
- content-app
volumes:
shared-file-store-volume:
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID0TCCAzqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwfzELMAkGA1UEBhMCR0Ix
CzAJBgNVBAgMAlVLMRMwEQYDVQQHDApNYWlkZW5oZWFkMR8wHQYDVQQKDBZBbGZy
ZXNjbyBTb2Z0d2FyZSBMdGQuMRAwDgYDVQQLDAdVbmtub3duMRswGQYDVQQDDBJD
dXN0b20gQWxmcmVzY28gQ0EwHhcNMTkwODMwMTMzNzQ3WhcNMjkwODI3MTMzNzQ3
WjByMQswCQYDVQQGEwJHQjELMAkGA1UECAwCVUsxHzAdBgNVBAoMFkFsZnJlc2Nv
IFNvZnR3YXJlIEx0ZC4xEDAOBgNVBAsMB1Vua25vd24xIzAhBgNVBAMMGkN1c3Rv
bSBBbGZyZXNjbyBSZXBvc2l0b3J5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQChncDS402ZkMx7DBJwDI1Ycs9MMotmqBcJg85GrGfw9Wpxgsxn3m1AuneBWTgN
3P8BYmxdL/uE8pV6KwWlvh3IPB6hv9PxpS9D9uDfaPmZcXKIQXbj440ysPtCKs6d
/czjcVAzoG4oq/XVAS3QPGK5WsqUOmvskES7Y0pkRLwpWQIDAQABo4IBZzCCAWMw
CQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgENBCYWJE9w
ZW5TU0wgR2VuZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUFz5n
fbUE7IRj4sQ0FKnMwSJdGy8wgbMGA1UdIwSBqzCBqIAUsA46Qj0+T/tpicaxqYYV
/hzfJgKhgYSkgYEwfzELMAkGA1UEBhMCR0IxCzAJBgNVBAgMAlVLMRMwEQYDVQQH
DApNYWlkZW5oZWFkMR8wHQYDVQQKDBZBbGZyZXNjbyBTb2Z0d2FyZSBMdGQuMRAw
DgYDVQQLDAdVbmtub3duMRswGQYDVQQDDBJDdXN0b20gQWxmcmVzY28gQ0GCCQCi
8OUigUs5TTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwFAYD
VR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4GBADWOrvgLnmxA7fqL
RDRVLI+OO5rtXLsnagb+MJBao7NYJsNADdugQ+MegSDLQQXCWb1ynZ6010a7aLP6
KeSRgqJxvfvuMyhWo0mmB9f4h1OhkLBFGVOaI4Jk3RTlzcrDTVUige9OBex7Pjjl
PCpxaGAbXG44RiFhxzNC63Eay6Om
-----END CERTIFICATE-----
@@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKGdwNLjTZmQzHsM
EnAMjVhyz0wyi2aoFwmDzkasZ/D1anGCzGfebUC6d4FZOA3c/wFibF0v+4TylXor
BaW+Hcg8HqG/0/GlL0P24N9o+ZlxcohBduPjjTKw+0Iqzp39zONxUDOgbiir9dUB
LdA8YrlaypQ6a+yQRLtjSmREvClZAgMBAAECgYAYr1m2XFWL8RvqZ2uhhalJKzAS
eV3lbiMmpuUo0kiF+1YoxEuoScbyLgj2zsPLCkhA0+GtUhjes5a1NEEGkcVGhA05
QxUSBMQ+aLu6b6XY4A2XklMaD+ScqqpEN4zAEniNrL4Hbgx9VlPtLl+dpKFoCn9Q
RJYzGvr2CGFK71VhoQJBANH/zszcjqwADA0iW5LrXIBJ/Xd7pQdBwX/DtqGcoUqm
abfCoGqhyE4wCspGff/56D3cZKPQsf9+AO+YGssRrBUCQQDFBMFyx2F+hdWhkdUG
fIBo7+D6GGP4Gjj/hw8YcD6zpVInU3ctuAjumAY0U2X5HzJMXKXY1QjrxLUmOSIG
AqU1AkBomcbkfCgEvLFECY0bjWix7ij2zvvQtYwwm8fokCA3EtUt1yAYfSVM7Nkz
EBHK4ywvRAxNHLLM1HKa5WTTKaZRAkEAw62EgP5b67D7TDyuSoHve8n8NglxiOJq
iAhZStl4vS5OmTaB4Quu+2JMjz3hwvtkFonSQrjb4mb90FfgXf3UnQJAKpW2mb3M
PjJec8f5vT16PNASSi+TiGAjRddMoG6AP4gcSlx3OZGupyJnlPU41nGuOlLDOB1d
gxp42gv4pSjERw==
-----END PRIVATE KEY-----
@@ -0,0 +1,81 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen *:<%=port%><% if (httpWebMode == 'https') { %> ssl<% } %>;
client_max_body_size 0;
set $allowOriginSite *;
proxy_pass_request_headers on;
proxy_pass_header Set-Cookie;
<% if (httpWebMode == 'https') { %>
ssl_certificate /etc/nginx/localhost.cer;
ssl_certificate_key /etc/nginx/localhost.key;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
ssl_protocols TLSv1.1 TLSv1.2;
<% } %>
# External settings, do not remove
#ENV_ACCESS_LOG
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_header Set-Cookie;
<% if (protectSolr == 'https') { %>
# Protect access to SOLR APIs
location ~ ^(/.*/service/api/solr/.*)$ {return 403;}
location ~ ^(/.*/s/api/solr/.*)$ {return 403;}
location ~ ^(/.*/wcservice/api/solr/.*)$ {return 403;}
location ~ ^(/.*/wcs/api/solr/.*)$ {return 403;}
location ~ ^(/.*/proxy/alfresco/api/solr/.*)$ {return 403 ;}
location ~ ^(/.*/-default-/proxy/alfresco/api/.*)$ {return 403;}
<% } %>
# Alfresco Repository
location /alfresco/ {
proxy_pass http://alfresco:8080;
}
# REST API (Swagger)
location /api-explorer/ {
proxy_pass http://alfresco:8080;
}
<% if (httpMode == 'http') { %>
# SOLR Web Console (Master)
location /solr/ {
proxy_pass http://solr6:8983;
# Basic authentication
auth_basic "Solr web console";
auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
}
<% } %>
# Alfresco Share Web App
location /share/ {
proxy_pass http://share:8080;
}
# Alfresco Content App
location / {
proxy_pass http://content-app:8080;
}
}
}
@@ -3,5 +3,10 @@ FROM <%=shareImage%>:${SHARE_TAG}
ARG TOMCAT_DIR=/usr/local/tomcat
<% if (httpWebMode == 'https') { %>
RUN sed -i '/Connector port="8080"/a scheme="https" secure="true"' /usr/local/tomcat/conf/server.xml && \
sed -i '/Connector port="8080"/a proxyName="localhost" proxyPort="<%=port%>"' /usr/local/tomcat/conf/server.xml
<% } %>
# Copy custom content forms to deployment folder
COPY model/* $TOMCAT_DIR/shared/classes/alfresco/web-extension/