Merge branch 'feature/v2.0.0-rc1' into develop

This commit is contained in:
Diego Lendoiro 2018-01-16 18:02:17 +01:00
commit bc3431d88c
12 changed files with 463 additions and 369 deletions

3
.gitignore vendored
View File

@ -27,3 +27,6 @@ fabric.properties
# Generated docker files # Generated docker files
conf/*.key conf/*.key
# src directory used for local development
src

View File

@ -1,30 +1,15 @@
FROM alpine:3.6 FROM php:7-fpm-alpine3.7
LABEL maintainer="diego@passbolt.com" LABEL MAINTAINER diego@passbolt.com
ENV PASSBOLT_VERSION 1.6.9 ENV PASSBOLT_URL https://github.com/passbolt/passbolt_api/archive/develop.tar.gz
ENV PASSBOLT_URL https://github.com/passbolt/passbolt_api/archive/v${PASSBOLT_VERSION}.tar.gz
ARG BASE_PHP_DEPS="php5-curl \ ARG PHP_EXTENSIONS="gd \
php5-common \ intl \
php5-gd \ pdo_mysql \
php5-intl \ xsl"
php5-json \
php5-mcrypt \
php5-mysql \
php5-xsl \
php5-fpm \
php5-phar \
php5-posix \
php5-xml \
php5-openssl \
php5-zlib \
php5-ctype \
php5-pdo \
php5-pdo_mysql \
php5-pear"
ARG PHP_GNUPG_DEPS="php5-dev \ ARG PHP_GNUPG_BUILD_DEPS="php7-dev \
make \ make \
gcc \ gcc \
g++ \ g++ \
@ -36,40 +21,35 @@ ARG PHP_GNUPG_DEPS="php5-dev \
zlib-dev \ zlib-dev \
file" file"
RUN apk add --no-cache $BASE_PHP_DEPS \ RUN apk add --no-cache $PHP_GNUPG_BUILD_DEPS \
sed \
coreutils \
tar \
bash \
curl \
nginx \ nginx \
gpgme \ gpgme \
gnupg1 \ gnupg1 \
recode \
libxml2 \
openssl \
libpcre32 \
mysql-client \ mysql-client \
ca-certificates libpng-dev \
icu-dev \
RUN apk add --no-cache $PHP_GNUPG_DEPS \ libxslt-dev \
&& ln -s /usr/bin/php5 /usr/bin/php \ libmcrypt-dev \
&& ln -s /usr/bin/phpize5 /usr/bin/phpize \ supervisor \
&& sed -i "s/ -n / /" $(which pecl) \ && pecl install gnupg redis mcrypt-snapshot \
&& pecl install gnupg \ && docker-php-ext-install -j4 $PHP_EXTENSIONS \
&& pecl install redis \ && docker-php-ext-enable $PHP_EXTENSIONS gnupg redis mcrypt \
&& echo "extension=gnupg.so" > /etc/php5/conf.d/gnupg.ini \ && apk del $PHP_GNUPG_BUILD_DEPS \
&& echo "extension=redis.so" > /etc/php5/conf.d/redis.ini \
&& apk del $PHP_GNUPG_DEPS \
&& curl -sS https://getcomposer.org/installer | php \ && curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer \ && mv composer.phar /usr/local/bin/composer
&& mkdir /var/www/passbolt \
RUN mkdir -p /var/www/passbolt \
&& curl -sSL $PASSBOLT_URL | tar zxf - -C /var/www/passbolt --strip-components 1 \ && curl -sSL $PASSBOLT_URL | tar zxf - -C /var/www/passbolt --strip-components 1 \
&& chown -R nginx:nginx /var/www/passbolt \ && cd /var/www/passbolt \
&& chmod -R +w /var/www/passbolt/app/tmp \ && composer install \
&& chmod +w /var/www/passbolt/app/webroot/img/public && chown -R www-data:www-data /var/www/passbolt \
&& chmod 775 $(find /var/www/passbolt/tmp -type d) \
&& chmod 664 $(find /var/www/passbolt/tmp -type f) \
&& chmod 775 $(find /var/www/passbolt/webroot/img/public -type d) \
&& chmod 664 $(find /var/www/passbolt/webroot/img/public -type f)
COPY conf/passbolt.conf /etc/nginx/conf.d/default.conf COPY conf/passbolt.conf /etc/nginx/conf.d/default.conf
COPY conf/supervisord.conf /etc/supervisord.conf
COPY bin/docker-entrypoint.sh /docker-entrypoint.sh COPY bin/docker-entrypoint.sh /docker-entrypoint.sh
EXPOSE 80 443 EXPOSE 80 443

8
Gemfile Normal file
View File

@ -0,0 +1,8 @@
source 'https://rubygems.org'
group :test do
gem 'docker-api'
gem 'rake'
gem 'serverspec'
gem 'pry'
end

58
Gemfile.lock Normal file
View File

@ -0,0 +1,58 @@
GEM
remote: https://rubygems.org/
specs:
coderay (1.1.2)
diff-lcs (1.3)
docker-api (1.34.0)
excon (>= 0.47.0)
multi_json
excon (0.60.0)
method_source (0.9.0)
multi_json (1.12.2)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (4.2.0)
net-telnet (0.1.1)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rake (12.3.0)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.0)
serverspec (2.41.3)
multi_json
rspec (~> 3.0)
rspec-its
specinfra (~> 2.72)
sfl (2.3)
specinfra (2.73.0)
net-scp
net-ssh (>= 2.7, < 5.0)
net-telnet
sfl
PLATFORMS
ruby
DEPENDENCIES
docker-api
pry
rake
serverspec
BUNDLED WITH
1.16.1

153
README.md
View File

@ -1,5 +1,9 @@
# Passbolt docker official image # Passbolt docker official image
# Warning
This is a work in progress branch use at your own risk.
# What is passbolt? # What is passbolt?
Passbolt is a free and open source password manager that allows team members to Passbolt is a free and open source password manager that allows team members to
@ -14,8 +18,6 @@ track issues and pull requests.
Users that do not require any special modifications are encouraged to `docker pull` the Users that do not require any special modifications are encouraged to `docker pull` the
[official docker image from the docker hub](https://hub.docker.com/r/passbolt/passbolt/). [official docker image from the docker hub](https://hub.docker.com/r/passbolt/passbolt/).
There is also a yet unofficial project to use [passbolt along with docker-compose](https://github.com/dlen/passbolt-compose) for easier the setup process.
# Build the image # Build the image
Inside the repo directory: Inside the repo directory:
@ -30,16 +32,22 @@ Passbolt requires mysql to be running. The following example use mysql official
with the default passbolt credentials. with the default passbolt credentials.
```bash ```bash
$ docker run -e MYSQL_ROOT_PASSWORD=<your_root_password> \ $ docker run -e MYSQL_ROOT_PASSWORD=<root_password> \
-e MYSQL_DATABASE=passbolt \ -e MYSQL_DATABASE=<mysql_database> \
-e MYSQL_USER=passbolt \ -e MYSQL_USER=<mysql_user> \
-e MYSQL_PASSWORD=P4ssb0lt \ -e MYSQL_PASSWORD=<mysql_password> \
mysql mysql
``` ```
Then you can start passbolt just by providing the database container ip in the `db_host` environment variable. Then you can start passbolt just by providing the database container ip in the `db_host` environment variable.
`$ docker run -e DB_HOST=<mysql_container_ip> passbolt:local` ```bash
$ docker run -e DATASOURCES_DEFAULT_HOST=<mysql_container_host> \
-e DATASOURCES_DEFAULT_PASSWORD=<mysql_password> \
-e DATASOURCES_DEFAULT_USERNAME=<mysql_user> \
-e DATASOURCES_DEFAULT_DATABASE=<mysql_database> \
passbolt:local
```
Once the process is done, just navigate to the following url in your browser: https://passbolt_container_ip Once the process is done, just navigate to the following url in your browser: https://passbolt_container_ip
@ -54,50 +62,39 @@ And access it using https://localhost:host_port
# Configure passbolt # Configure passbolt
## Environment variables ## Environment variables reference
Passbolt docker image provides several environment variables to configure different aspects: Passbolt docker image provides several environment variables to configure different aspects:
### GnuPG key creation related variables * APP_FULL_BASE_URL: Defines Passbolt base url (Example https://yourdomain.com)
* DATASOURCES_DEFAULT_HOST: database hostname (defaults to localhost)
* KEY_LENGTH: gpg desired key length * DATASOURCES_DEFAULT_PORT: database port (defaults to 3306)
* SUBKEY_LENGTH: gpg desired subkey length * DATASOURCES_DEFAULT_USERNAME: database username (defaults to my_app)
* KEY_NAME: key owner name * DATASOURCES_DEFAULT_PASSWORD: database password (defaults to secret)
* KEY_EMAIL: key owner email address * DATASOURCES_DEFAULT_DATABASE: database name (defaults to my_app)
* KEY_EXPIRATION: key expiration date * EMAIL_DEFAULT_FROM: from email address (defaults to contact@mydomain.local)
* EMAIL_DEFAULT_TRANSPORT: sets transport method (defaults to default)
### App file variables * EMAIL_TRANSPORT_DEFAULT_HOST: server hostname (defaults to localhost)
* EMAIL_TRANSPORT_DEFAULT_PORT: server port (defaults to 25)
* FINGERPRINT: GnuPG fingerprint * EMAIL_TRANSPORT_DEFAULT_TIMEOUT: timeout (defaults to 30)
* REGISTRATION: Defines if users can register (defaults to false) * EMAIL_TRANSPORT_DEFAULT_USERNAME: username for email server auth (defaults to null)
* SSL: Forces passbolt to redirect to SSL any non-SSL request * EMAIL_TRANSPORT_DEFAULT_PASSWORD: password for email server auth (defaults to null)
* EMAIL_TRANSPORT_DEFAULT_CLIENT: client (defaults to null)
### Core file variables * EMAIL_TRANSPORT_DEFAULT_TLS: set tls (defaults to null)
* EMAIL_TRANSPORT_DEFAULT_URL: set url (defaults to null)
* SALT: a random string used by cakephp in security hashing methods * GNUPGHOME: Path to gnupghome directory (defaults to web_user_home_directory/.gnupg )
* CIPHERSEED: a random string used by cakephp to encrypt/decrypt strings * PASSBOLT_KEY_LENGTH: gpg desired key length
* URL: URL of the passbolt installation (defaults to http://passbolt.local) * PASSBOLT_SUBKEY_LENGTH: gpg desired subkey length
* PASSBOLT_KEY_NAME: key owner name
### Database variables * PASSBOLT_KEY_EMAIL: key owner email address
* PASSBOLT_KEY_EXPIRATION: key expiration date
* DB_HOST: database hostname This param has to be specified either using env var or in database.php (defaults to passbolt.local) * PASSBOLT_GPG_SERVER_KEY_FINGERPRINT: GnuPG fingerprint
* DB_PORT: database port (defaults to 3306) * PASSBOLT_GPG_SERVER_KEY_PUBLIC: Path to GnuPG public server key
* DB_USER: database username (defaults to passbolt) * PASSBOLT_GPG_SERVER_KEY_PRIVATE: Path to GnuPG private server key
* DB_PASS: database password (defaults to P4ssb0lt) * PASSBOLT_REGISTRATION_PUBLIC: Defines if users can register (defaults to false)
* DB_NAME: database name (defaults to passbolt) * PASSBOLT_SSL_FORCE: Forces passbolt to redirect to SSL any non-SSL request
* PASSBOLT_SECURITY_SET_HEADERS: Forces passbolt to send CSP Headers (defaults to true)
### Email variables * SECURITY_SALT: A random number user in security hashing methods.
* EMAIL_TRANSPORT: transport protocol ( defaults to Smtp)
* EMAIL_FROM: from email address ( defaults to contact@mydomain.local)
* EMAIL_HOST: server hostname ( defaults to localhost)
* EMAIL_PORT: server port ( defaults to 587)
* EMAIL_TIMEOUT: timeout ( defaults to 30s)
* EMAIL_AUTH: disable smtp auth ( defaults to true)
* EMAIL_USERNAME: username for email server auth ( defaults to email_user)
* EMAIL_PASSWORD: password for email server auth ( defaults to email_password)
* EMAIL_CLIENT: hostname to send as smtp helo ( defaults to null)
* EMAIL_TLS: set tls, boolean ( defaults to false)
## Advanced configuration ## Advanced configuration
@ -106,12 +103,9 @@ It it possible to mount the desired configuration files as volumes.
### Configuration files subject to be persisted: ### Configuration files subject to be persisted:
* /var/www/passbolt/app/Config/app.php * /var/www/passbolt/config/app.php
* /var/www/passbolt/app/Config/core.php * /var/www/passbolt/config/gpg/serverkey.asc
* /var/www/passbolt/app/Config/database.php * /var/www/passbolt/config/gpg/serverkey_private.asc
* /var/www/passbolt/app/Config/email.php
* /var/www/passbolt/app/Config/gpg/serverkey.asc
* /var/www/passbolt/app/Config/gpg/serverkey.private.asc
* /var/www/passbolt/app/webroot/img/public/images * /var/www/passbolt/app/webroot/img/public/images
### SSL certificate files ### SSL certificate files
@ -121,57 +115,6 @@ It is also possible to mount a ssl certificate on the following paths:
* /etc/ssl/certs/certificate.crt * /etc/ssl/certs/certificate.crt
* /etc/ssl/certs/certificate.key * /etc/ssl/certs/certificate.key
# Examples
For the following examples it is assumed that passbolt container image has been built from this repo following the instructions
described on the [Build](#build-the-image) section.
In the following example passbolt is launched with the defaults enabled usind mysql official docker container to store passbolt data:
```bash
$ docker run -e MYSQL_ROOT_PASSWORD=c0mplexp4ss \
-e MYSQL_DATABASE=passbolt \
-e MYSQL_USER=passbolt \
-e MYSQL_PASSWORD=P4ssb0lt \
mysql
```
Once mysql container is running we should extract its ip address. Let's assume 172.17.0.2 for this example
`$ docker run -e DB_HOST=172.17.0.2 passbolt:local`
Point your browser to the passbolt container ip or localhost:exposed_port.
## Advanced configuration
In the following example passbolt is launched with a customized setup mounting and persisting configuration files. We also make use of
mysql official docker container to store passbolt data.
```bash
$ docker run -e MYSQL_ROOT_PASSWORD=c0mplexp4ss \
-e MYSQL_DATABASE=passbolt \
-e MYSQL_USER=passbolt \
-e MYSQL_PASSWORD=P4ssb0lt \
mysql
```
Using docker inspect or any other method you can get the ip address of the mysql container. This example uses 172.17.0.2.
Once this container is running and you have the mysql ip address we run passbolt container mounting all configuration files stored
under a example conf directory in $PWD
```bash
$ docker run -v $PWD/conf/app.php:/var/www/passbolt/app/Config/app.php \
-v $PWD/conf/core.php:/var/www/passbolt/app/Config/core.php \
-v $PWD/conf/database.php:/var/www/passbolt/app/Config/database.php \
-v $PWD/conf/email.php:/var/www/passbolt/app/Config/email.php \
-v $PWD/conf/private.asc:/var/www/passbolt/app/Config/gpg/serverkey.private.asc \
-v $PWD/conf/public.asc:/var/www/passbolt/app/Config/gpg/serverkey.asc \
passbolt:local
```
Navigate with the browser to the passbolt container ip or localhost:exposed_port
# Requirements: # Requirements:
* rng-tools are required on host machine to speed up entropy generation on containers. This way gpg key creation on passbolt container will be faster. * rng-tools are required on host machine to speed up entropy generation on containers. This way gpg key creation on passbolt container will be faster.

27
Rakefile Normal file
View File

@ -0,0 +1,27 @@
require 'rake'
require 'rspec/core/rake_task'
task :spec => 'spec:all'
task :default => :spec
namespace :spec do
targets = []
Dir.glob('./spec/*').each do |dir|
next unless File.directory?(dir)
target = File.basename(dir)
target = "_#{target}" if target == "default"
targets << target
end
task :all => targets
task :default => :all
targets.each do |target|
original_target = target == "_default" ? target[1..-1] : target
desc "Run serverspec tests to #{original_target}"
RSpec::Core::RakeTask.new(target.to_sym) do |t|
ENV['TARGET_HOST'] = original_target
t.pattern = "spec/#{original_target}/*_spec.rb"
end
end
end

View File

@ -1,232 +1,99 @@
#!/bin/bash #!/usr/bin/env sh
set -eo pipefail set -eo pipefail
gpg_private_key=/var/www/passbolt/app/Config/gpg/serverkey.private.asc gpg_private_key="${PASSBOLT_GPG_SERVER_KEY_PRIVATE:-/var/www/passbolt/config/gpg/serverkey_private.asc}"
gpg_public_key=/var/www/passbolt/app/Config/gpg/serverkey.asc gpg_public_key="${PASSBOLT_GPG_SERVER_KEY_PUBLIC:-/var/www/passbolt/config/gpg/serverkey.asc}"
gpg=$(which gpg)
core_config='/var/www/passbolt/app/Config/core.php'
db_config='/var/www/passbolt/app/Config/database.php'
app_config='/var/www/passbolt/app/Config/app.php'
email_config='/var/www/passbolt/app/Config/email.php'
ssl_key='/etc/ssl/certs/certificate.key' ssl_key='/etc/ssl/certs/certificate.key'
ssl_cert='/etc/ssl/certs/certificate.crt' ssl_cert='/etc/ssl/certs/certificate.crt'
gpg_gen_key() { gpg_gen_key() {
su -m -c "$gpg --batch --gen-key <<EOF key_email="${PASSBOLT_KEY_EMAIL:-passbolt@yourdomain.com}"
Key-Type: 1 key_name="${PASSBOLT_KEY_NAME:-Passbolt default user}"
Key-Length: ${KEY_LENGTH:-2048} key_length="${PASSBOLT_KEY_LENGTH:-2048}"
Subkey-Type: 1 subkey_length="${PASSBOLT_SUBKEY_LENGTH:-2048}"
Subkey-Length: ${SUBKEY_LENGTH:-2048} expiration="${PASSBOLT_KEY_EXPIRATION:-0}"
Name-Real: ${KEY_NAME:-Passbolt default user}
Name-Email: ${KEY_EMAIL:-passbolt@yourdomain.com}
Expire-Date: ${KEY_EXPIRATION:-0}
%commit
EOF" -ls /bin/bash nginx
su -m -c "$gpg --armor --export-secret-keys $KEY_EMAIL > $gpg_private_key" -ls /bin/bash nginx su -m -c "gpg --batch --gen-key <<EOF
su -m -c "$gpg --armor --export $KEY_EMAIL > $gpg_public_key" -ls /bin/bash nginx Key-Type: 1
Key-Length: $key_length
Subkey-Type: 1
Subkey-Length: $subkey_length
Name-Real: $key_name
Name-Email: $key_email
Expire-Date: $expiration
%commit
EOF" -ls /bin/sh www-data
su -c "gpg --armor --export-secret-keys $key_email > $gpg_private_key" -ls /bin/sh www-data
su -c "gpg --armor --export $key_email > $gpg_public_key" -ls /bin/sh www-data
} }
gpg_import_key() { gpg_import_key() {
key_id=$(su -m -c "gpg --with-colons $gpg_private_key | grep sec |cut -f5 -d:" -ls /bin/sh www-data)
local key_id=$(su -m -c "gpg --with-colons $gpg_private_key | grep sec |cut -f5 -d:" -ls /bin/bash nginx) su -c "gpg --batch --import $gpg_public_key" -ls /bin/sh www-data
su -c "gpg -K $key_id" -ls /bin/sh www-data || su -m -c "gpg --batch --import $gpg_private_key" -ls /bin/sh www-data
su -m -c "$gpg --batch --import $gpg_public_key" -ls /bin/bash nginx
su -m -c "gpg -K $key_id" -ls /bin/bash nginx || su -m -c "$gpg --batch --import $gpg_private_key" -ls /bin/bash nginx
}
core_setup() {
#Env vars:
# SALT
# CIPHERSEED
# URL
local default_salt='DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi'
local default_seed='76859309657453542496749683645'
local default_url='http://passbolt.local'
cp $core_config{.default,}
sed -i s:$default_salt:${SALT:-$default_salt}:g $core_config
sed -i s:$default_seed:${CIPHERSEED:-$default_seed}:g $core_config
sed -i "/example.com/ s:\/\/::" $core_config
sed -i "s|http://example.com|${URL:-$default_url}|g" $core_config
}
db_setup() {
#Env vars:
# DB_HOST
# DB_USER
# DB_PASS
# DB_NAME
local default_host='localhost'
local default_user='user'
local default_pass='password'
local default_db='database_name'
cp $db_config{.default,}
sed -i "/$default_host/a\ \t\t'port' => '${DB_PORT:-3306}'," $db_config
sed -i s:$default_host:${DB_HOST:-db}:g $db_config
sed -i s:$default_user:${DB_USER:-passbolt}:g $db_config
sed -i s:$default_pass\',:${DB_PASS:-P4ssb0lt}\',:g $db_config
sed -i s:$default_db:${DB_NAME:-passbolt}:g $db_config
}
app_setup() {
#Env vars:
# FINGERPRINT
# REGISTRATION
# SSL
local default_home='/home/www-data/.gnupg'
local default_public_key='unsecure.key'
local default_private_key='unsecure_private.key'
local default_fingerprint='2FC8945833C51946E937F9FED47B0811573EE67E'
local gpg_home='/var/lib/nginx/.gnupg'
local auto_fingerprint=$(su -m -c "$gpg --fingerprint |grep fingerprint| awk '{for(i=4;i<=NF;++i)printf \$i}'" -ls /bin/bash nginx)
cp $app_config{.default,}
sed -i s:$default_home:$gpg_home:g $app_config
sed -i s:$default_public_key:serverkey.asc:g $app_config
sed -i s:$default_private_key:serverkey.private.asc:g $app_config
sed -i s:$default_fingerprint:${FINGERPRINT:-$auto_fingerprint}:g $app_config
sed -i "/force/ s:true:${SSL:-true}:" $app_config
sed -i "/'registration'/{n; s:false:${REGISTRATION:-false}:}" $app_config
}
email_setup() {
#Env vars:
# EMAIL_TRANSPORT
# EMAIL_FROM
# EMAIL_HOST
# EMAIL_PORT
# EMAIL_TIMEOUT
# EMAIL_AUTH
# EMAIL_USERNAME
# EMAIL_PASSWORD
# EMAIL_CLIENT
# EMAIL_TLS
local default_transport='Smtp'
local default_from='contact@passbolt.com'
local default_host='smtp.mandrillapp.com'
local default_port='587'
local default_timeout='30'
local default_username="''"
local default_password="''"
local default_client=null
cp $email_config{.default,}
sed -i s:$default_transport:${EMAIL_TRANSPORT:-Smtp}:g $email_config
sed -i s:$default_from:${EMAIL_FROM:-contact@mydomain.local}:g $email_config
sed -i s:$default_host:${EMAIL_HOST:-localhost}:g $email_config
sed -i s:$default_port:${EMAIL_PORT:-587}:g $email_config
sed -i s:$default_timeout:${EMAIL_TIMEOUT:-30}:g $email_config
if [ "$EMAIL_AUTH" = "false" ] ; then
sed -i "0,/"$default_username"/s:"$default_username":null:" $email_config
sed -i "0,/"$default_password"/s:"$default_password":null:" $email_config
else
sed -i "0,/"$default_username"/s:"$default_username":'${EMAIL_USERNAME:-email_user}':" $email_config
sed -i "0,/"$default_password"/s:"$default_password":'${EMAIL_PASSWORD:-email_password}':" $email_config
fi
if [ -n "$EMAIL_CLIENT" ] ; then
sed -i "0,/"$default_client"/s:"$default_client":'$EMAIL_CLIENT':" $email_config
fi
sed -i "0,/tls/s:false:${EMAIL_TLS:-false}:" $email_config
} }
gen_ssl_cert() { gen_ssl_cert() {
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
-subj "/C=FR/ST=Denial/L=Springfield/O=Dis/CN=www.passbolt.local" \ -subj '/C=FR/ST=Denial/L=Springfield/O=Dis/CN=www.passbolt.local' \
-keyout $ssl_key -out $ssl_cert -keyout $ssl_key -out $ssl_cert
} }
install() { install() {
local database_host=${DB_HOST:-$(cat $db_config | grep -m1 "'host'" | sed -r "s/\s*'host' => '(.*)',/\1/")} tables=$(mysql \
local database_port=${DB_PORT:-$(cat $db_config | grep -m1 "'port' => '\d" | sed -r "s/\s*'port' => '(.*)',/\1/")} -u "$DATASOURCES_DEFAULT_USERNAME" \
local database_user=${DB_USER:-$(cat $db_config | grep -m1 "'login'" | sed -r "s/\s*'login' => '(.*)',/\1/")} -h "$DATASOURCES_DEFAULT_HOST" \
local database_pass=${DB_PASS:-$(cat $db_config | grep -m1 "'password'" | sed -r "s/\s*'password' => '(.*)',/\1/")} -P "$DATASOURCES_DEFAULT_PORT" \
local database_name=${DB_NAME:-$(cat $db_config | grep -m1 "'database'" | sed -r "s/\s*'database' => '(.*)',/\1/")} -BN -e "SHOW TABLES FROM $DATASOURCES_DEFAULT_DATABASE" \
tables=$(mysql -u ${database_user:-passbolt} -h $database_host -P ${database_port:-3306} -p -BN -e "SHOW TABLES FROM ${database_name:-passbolt}" -p${database_pass:-P4ssb0lt} |wc -l) -p"$DATASOURCES_DEFAULT_PASSWORD" |wc -l)
app_config="/var/www/passbolt/config/app.php"
if [ $tables -eq 0 ]; then if [ ! -f "$app_config" ]; then
su -c "/var/www/passbolt/app/Console/cake install --send-anonymous-statistics true --no-admin" -ls /bin/bash nginx su -c 'cp /var/www/passbolt/config/app.default.php /var/www/passbolt/config/app.php' -s /bin/sh www-data
fi
if [ -z "$PASSBOLT_GPG_SERVER_KEY_FINGERPRINT" ]; then
gpg_auto_fingerprint="$(su -c "gpg --with-fingerprint $gpg_public_key | grep fingerprint | awk '{for(i=4;i<=NF;++i)printf \$i}'" -ls /bin/sh www-data)"
export PASSBOLT_GPG_SERVER_KEY_FINGERPRINT=$gpg_auto_fingerprint
fi
if [ "$tables" -eq 0 ]; then
su -c '/var/www/passbolt/bin/cake passbolt install --no-admin --force' -s /bin/sh www-data
else else
echo "Enjoy! ☮" echo "Enjoy! ☮"
fi fi
} }
php_fpm_setup() {
sed -i '/^user\s/ s:nobody:nginx:g' /etc/php5/php-fpm.conf
sed -i '/^group\s/ s:nobody:nginx:g' /etc/php5/php-fpm.conf
cp /etc/php5/php-fpm.conf /etc/php5/fpm.d/www.conf
sed -i '/^include\s/ s:^:#:' /etc/php5/fpm.d/www.conf
}
check_permissions() {
chown -R nginx:nginx /var/www/passbolt
chmod -R +w /var/www/passbolt/app/tmp
chmod +w /var/www/passbolt/app/webroot/img/public
}
email_cron_job() { email_cron_job() {
local root_crontab='/etc/crontabs/root' root_crontab='/etc/crontabs/root'
local cron_task_dir='/etc/periodic/1min' cron_task_dir='/etc/periodic/1min'
local cron_task='/etc/periodic/1min/email_queue_processing' cron_task='/etc/periodic/1min/email_queue_processing'
local process_email="/var/www/passbolt/app/Console/cake EmailQueue.sender --quiet" process_email="/var/www/passbolt/bin/cake EmailQueue.sender --quiet"
mkdir -p $cron_task_dir mkdir -p $cron_task_dir
echo "* * * * * run-parts $cron_task_dir" >> $root_crontab
if ! grep $cron_task_dir $root_crontab > /dev/null; then
echo "* * * * * run-parts $cron_task_dir" >> $root_crontab
fi
echo "#!/bin/sh" > $cron_task echo "#!/bin/sh" > $cron_task
chmod +x $cron_task chmod +x $cron_task
echo "su -c \"$process_email\" -ls /bin/bash nginx" >> $cron_task echo "su -c \"$process_email\" -s /bin/sh www-data" >> $cron_task
crond -f -c /etc/crontabs &
} }
if [ ! -f $gpg_private_key ] && [ ! -L $gpg_private_key ] || \ if [ ! -f "$gpg_private_key" ] && [ ! -L "$gpg_private_key" ] || \
[ ! -f $gpg_public_key ] && [ ! -L $gpg_public_key ]; then [ ! -f "$gpg_public_key" ] && [ ! -L "$gpg_public_key" ]; then
gpg_gen_key gpg_gen_key
gpg_import_key
else else
gpg_import_key gpg_import_key
fi fi
if [ ! -f $core_config ] && [ ! -L $core_config ]; then if [ ! -f "$ssl_key" ] && [ ! -L "$ssl_key" ] && \
core_setup [ ! -f "$ssl_cert" ] && [ ! -L "$ssl_cert" ]; then
fi
if [ ! -f $db_config ] && [ ! -L $db_config ]; then
db_setup
fi
if [ ! -f $app_config ] && [ ! -L $app_config ]; then
app_setup
fi
if [ ! -f $email_config ] && [ ! -L $email_config ]; then
email_setup
fi
if [ ! -f $ssl_key ] && [ ! -L $ssl_key ] && \
[ ! -f $ssl_cert ] && [ ! -L $ssl_cert ]; then
gen_ssl_cert gen_ssl_cert
fi fi
check_permissions
php_fpm_setup
install install
php-fpm5
email_cron_job email_cron_job
nginx -g "pid /tmp/nginx.pid; daemon off;" /usr/bin/supervisord -n -c /etc/supervisord.conf

View File

@ -12,18 +12,6 @@ server {
root /var/www/passbolt; root /var/www/passbolt;
# X-Frame-Options is to prevent from clickJacking attack
add_header X-Frame-Options SAMEORIGIN;
# disable content-type sniffing on some browsers.
add_header X-Content-Type-Options nosniff;
# This header enables the Cross-site scripting (XSS) filter
add_header X-XSS-Protection "1; mode=block";
# This will enforce HTTP browsing into HTTPS and avoid ssl stripping attack
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
location / { location / {
try_files $uri $uri/ /index.php?$args; try_files $uri $uri/ /index.php?$args;
index index.php; index index.php;
@ -38,10 +26,11 @@ server {
fastcgi_param SERVER_NAME $http_host; fastcgi_param SERVER_NAME $http_host;
} }
location ~* \.(jpe?g|woff|woff2|ttf|gif|png|bmp|ico|css|js|json|pdf|zip|htm|html|docx?|xlsx?|pptx?|txt|wav|swf|svg|avi|mp\d)$ { location ~* \.(jpe?g|woff|woff2|ttf|gif|png|bmp|ico|css|js|ejs|json|pdf|zip|htm|html|docx?|xlsx?|pptx?|txt|wav|swf|svg|avi|mp\d)$ {
access_log off; access_log off;
log_not_found off; log_not_found off;
try_files $uri /app/webroot/$uri /index.php?$args; try_files $uri /webroot/$uri /index.php?$args;
#try_files $uri /app/webroot/$uri /index.php?$args;
} }
} }
@ -56,21 +45,9 @@ server {
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_session_tickets off; ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
root /var/www/passbolt; root /var/www/passbolt;
# X-Frame-Options is to prevent from clickJacking attack
add_header X-Frame-Options SAMEORIGIN;
# disable content-type sniffing on some browsers.
add_header X-Content-Type-Options nosniff;
# This header enables the Cross-site scripting (XSS) filter
add_header X-XSS-Protection "1; mode=block";
location / { location / {
try_files $uri $uri/ /index.php?$args; try_files $uri $uri/ /index.php?$args;
index index.php; index index.php;
@ -88,6 +65,6 @@ server {
location ~* \.(jpe?g|woff|woff2|ttf|gif|png|bmp|ico|css|js|json|pdf|zip|htm|html|docx?|xlsx?|pptx?|txt|wav|swf|svg|avi|mp\d)$ { location ~* \.(jpe?g|woff|woff2|ttf|gif|png|bmp|ico|css|js|json|pdf|zip|htm|html|docx?|xlsx?|pptx?|txt|wav|swf|svg|avi|mp\d)$ {
access_log off; access_log off;
log_not_found off; log_not_found off;
try_files $uri /app/webroot/$uri /index.php?$args; try_files $uri /webroot/$uri /index.php?$args;
} }
} }

36
conf/supervisord.conf Normal file
View File

@ -0,0 +1,36 @@
[unix_http_server]
file=/tmp/supervisor.sock ; (the path to the socket file)
[supervisord]
logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
[program:php-fpm]
command=php-fpm
autostart=true
priority=5
[program:nginx]
command=nginx -g "pid /tmp/nginx.pid; daemon off;"
autostart=true
priority=10
[program:crond]
command=crond -f -c /etc/crontabs
autostart=true
priority=20

View File

@ -0,0 +1,101 @@
require 'spec_helper'
describe 'Dockerfile' do
before(:all) do
set :env, {
'DATASOURCES_DEFAULT_HOST' => '172.17.0.2',
'DATASOURCES_DEFAULT_PASSWORD' => 'P4ssb0lt',
'DATASOURCES_DEFAULT_USERNAME' => 'passbolt',
'DATASOURCES_DEFAULT_DATABASE' => 'passbolt',
'PASSBOLT_GPG_KEYRING' => '/var/lib/nginx/.gnupg'
}
@image = Docker::Image.build_from_dir(ROOT_DOCKERFILES)
set :docker_image, @image.id
set :docker_container_create_options, { 'Cmd' => '/bin/sh' }
end
let(:nginx_conf) { '/etc/nginx/nginx.conf' }
let(:site_conf) { '/etc/nginx/conf.d/default.conf' }
let(:passbolt_home) { '/var/www/passbolt' }
let(:passbolt_tmp) { '/var/www/passbolt/tmp' }
let(:passbolt_image) { '/var/www/passbolt/webroot/img/public' }
let(:passbolt_owner) { 'www-data' }
let(:exposed_ports) { [ '80', '443' ] }
let(:composer) { '/usr/local/bin/composer'}
let(:php_extensions) { [
'curl', 'gd', 'intl', 'json', 'mcrypt', 'mysqlnd', 'xsl', 'phar',
'posix', 'xml', 'xsl', 'zlib', 'ctype', 'pdo', 'gnupg', 'pdo_mysql'
] }
describe 'passbolt required php extensions' do
it 'has php extensions installed' do
php_extensions.each do |ext|
expect(command("php --ri #{ext}").exit_status).to eq 0
end
end
end
describe 'php composer' do
it 'is installed' do
expect(file(composer)).to be_executable
end
end
describe 'supervisor' do
it 'is installed' do
expect(package('supervisor')).to be_installed
end
end
describe 'passbolt directory structure' do
it 'must exist and be directories' do
expect(file(passbolt_home)).to be_a_directory
expect(file(passbolt_tmp)).to be_a_directory
expect(file(passbolt_image)).to be_a_directory
end
it 'must be owned by correct user' do
expect(file(passbolt_home)).to be_owned_by(passbolt_owner)
expect(file(passbolt_tmp)).to be_owned_by(passbolt_owner)
expect(file(passbolt_image)).to be_owned_by(passbolt_owner)
end
it 'must have the correct permissions on tmp' do
expect(file(passbolt_tmp)).to be_mode('775')
end
it 'must have the correct permissions on img' do
expect(file(passbolt_image)).to be_mode('775')
end
end
describe 'nginx configuration' do
it 'is installed correctly' do
expect(file(nginx_conf)).to exist
end
it 'has the correct permissions' do
expect(file(nginx_conf)).to be_owned_by 'root'
end
end
describe 'nginx site configuration' do
it 'is installed correctly' do
expect(file(site_conf)).to exist
end
it 'has the correct permissions' do
expect(file(site_conf)).to be_owned_by 'root'
end
end
describe 'ports exposed' do
it 'exposes port' do
exposed_ports.each do |port|
expect(@image.json['ContainerConfig']['ExposedPorts']).to include("#{port}/tcp")
end
end
end
end

View File

@ -0,0 +1,85 @@
require 'spec_helper'
describe 'passbolt_api service' do
before(:all) do
@mysql = Docker::Container.create(
'Env' => [
'MYSQL_ROOT_PASSWORD=test',
'MYSQL_DATABASE=passbolt',
'MYSQL_USER=passbolt',
'MYSQL_PASSWORD=P4ssb0lt'
],
"Healthcheck" => {
"Test": [
"CMD-SHELL",
"mysqladmin ping --silent"
]
},
'Image' => 'mysql')
@mysql.start
while @mysql.json['State']['Health']['Status'] != 'healthy'
sleep 1
end
@image = Docker::Image.build_from_dir(ROOT_DOCKERFILES)
@container = Docker::Container.create(
'Env' => [
"DATASOURCES_DEFAULT_HOST=#{@mysql.json['NetworkSettings']['IPAddress']}",
'DATASOURCES_DEFAULT_PASSWORD=P4ssb0lt',
'DATASOURCES_DEFAULT_USERNAME=passbolt',
'DATASOURCES_DEFAULT_DATABASE=passbolt',
],
'Image' => @image.id)
@container.start
@container.logs(stdout: true)
set :docker_container, @container.id
sleep 17
end
after(:all) do
@mysql.kill
@container.kill
end
let(:http_path) { "/healthcheck/status.json" }
let(:healthcheck) { 'curl -s -o /dev/null -w "%{http_code}" http://localhost/healthcheck/status.json' }
describe 'php service' do
it 'is running supervised' do
expect(process('php-fpm')).to be_running.under('supervisor')
end
it 'has its port open' do
expect(port(9000)).to be_listening.with('tcp')
end
end
describe 'email cron' do
it 'is running supervised' do
expect(service('crond')).to be_running.under('supervisor')
end
end
describe 'web service' do
it 'is running supervised' do
expect(service('nginx')).to be_running.under('supervisor')
end
it 'is listening on port 80' do
expect(port(80)).to be_listening.with('tcp')
end
it 'is listening on port 443' do
expect(port(443)).to be_listening.with('tcp')
end
end
describe 'passbolt status' do
it 'returns 200' do
expect(command(healthcheck).stdout).to eq '200'
end
end
end

9
spec/spec_helper.rb Normal file
View File

@ -0,0 +1,9 @@
require 'serverspec'
require 'docker'
ROOT_DOCKERFILES = File.expand_path('../../', __FILE__)
set :backend, :docker
Docker.options[:read_timeout] = 3600
Docker.options[:write_timeout] = 3600