diff --git a/.gitignore b/.gitignore index d3b01e2..090b678 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ src # docker compose specific dev/.env + +# Vim session files +*.vim diff --git a/CHANGELOG.md b/CHANGELOG.md index 7357e47..1ab32cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased](https://github.com/passbolt/passbolt_docker/compare/v3.9.4...HEAD) +## [Unreleased](https://github.com/passbolt/passbolt_docker/compare/v3.10.0...HEAD) + +## [3.10.0](https://github.com/passbolt/passbolt_docker/compare/v3.9.4...v3.10.0) - 2023-05-02 + +### Added +- Make rootless docker image to own the supervisor files [#197](https://github.com/passbolt/passbolt_docker/pull/197) ## [3.9.4](https://github.com/passbolt/passbolt_docker/compare/v3.9.3...v3.9.4) - 2023-04-18 diff --git a/Gemfile.lock b/Gemfile.lock index 3bce6b8..36202ac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,12 +6,12 @@ GEM docker-api (2.2.0) excon (>= 0.47.0) multi_json - excon (0.98.0) + excon (0.99.0) method_source (1.0.0) multi_json (1.15.0) net-scp (4.0.0) net-ssh (>= 2.6.5, < 8.0.0) - net-ssh (7.0.1) + net-ssh (7.1.0) net-telnet (0.1.1) pry (0.14.2) coderay (~> 1.1) @@ -21,25 +21,25 @@ GEM rspec-core (~> 3.12.0) rspec-expectations (~> 3.12.0) rspec-mocks (~> 3.12.0) - rspec-core (3.12.0) + rspec-core (3.12.2) rspec-support (~> 3.12.0) - rspec-expectations (3.12.2) + rspec-expectations (3.12.3) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.12.3) + rspec-mocks (3.12.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) rspec-support (3.12.0) - serverspec (2.42.1) + serverspec (2.42.2) multi_json rspec (~> 3.0) rspec-its specinfra (~> 2.72) sfl (2.3) - specinfra (2.84.1) + specinfra (2.85.0) net-scp net-ssh (>= 2.7) net-telnet (= 0.1.1) diff --git a/debian/Dockerfile b/debian/Dockerfile index d647555..2e71234 100644 --- a/debian/Dockerfile +++ b/debian/Dockerfile @@ -15,32 +15,32 @@ ENV PASSBOLT_FLAVOUR=$PASSBOLT_FLAVOUR ENV PASSBOLT_PKG="passbolt-$PASSBOLT_FLAVOUR-server" RUN apt-get update \ - && DEBIAN_FRONTEND=non-interactive apt-get -y install \ - ca-certificates \ - gnupg \ - && apt-key adv --keyserver $PASSBOLT_SERVER_KEY --recv-keys $PASSBOLT_PKG_KEY \ - && echo "deb $PASSBOLT_REPO_URL $PASSBOLT_DISTRO $PASSBOLT_COMPONENT" > /etc/apt/sources.list.d/passbolt.list \ - && apt-get update \ - && DEBIAN_FRONTEND=non-interactive apt-get -y install --no-install-recommends \ - nginx \ - $PASSBOLT_PKG \ - supervisor \ - curl \ - && rm -f /etc/passbolt/jwt/* \ - && rm /etc/nginx/sites-enabled/default \ - && mkdir /run/php \ - && cp /usr/share/passbolt/examples/nginx-passbolt-ssl.conf /etc/nginx/snippets/passbolt-ssl.conf \ - && sed -i 's,;clear_env = no,clear_env = no,' /etc/php/$PHP_VERSION/fpm/pool.d/www.conf \ - && sed -i 's,# include __PASSBOLT_SSL__,include /etc/nginx/snippets/passbolt-ssl.conf;,' /etc/nginx/sites-enabled/nginx-passbolt.conf \ - && sed -i '/listen \[\:\:\]\:443 ssl http2;/a listen 443 ssl http2;' /etc/nginx/snippets/passbolt-ssl.conf \ - && sed -i 's,__CERT_PATH__,/etc/ssl/certs/certificate.crt;,' /etc/nginx/snippets/passbolt-ssl.conf \ - && sed -i 's,__KEY_PATH__,/etc/ssl/certs/certificate.key;,' /etc/nginx/snippets/passbolt-ssl.conf \ - && sed -i 's,www-data.*$,root su -s /bin/bash -c ". /etc/environment \&\& $PASSBOLT_BASE_DIR/bin/cron" www-data >/proc/1/fd/1 2>\&1,' /etc/cron.d/$PASSBOLT_PKG \ - && sed -i 's/# server_tokens/server_tokens/' /etc/nginx/nginx.conf \ - && ln -sf /dev/stdout /var/log/nginx/passbolt-access.log \ - && ln -sf /dev/stderr /var/log/nginx/passbolt-error.log \ - && ln -sf /dev/stderr /var/log/passbolt/error.log \ - && ln -sf /dev/stderr /var/log/php$PHP_VERSION-fpm.log + && DEBIAN_FRONTEND=non-interactive apt-get -y install \ + ca-certificates \ + gnupg \ + && apt-key adv --keyserver $PASSBOLT_SERVER_KEY --recv-keys $PASSBOLT_PKG_KEY \ + && echo "deb $PASSBOLT_REPO_URL $PASSBOLT_DISTRO $PASSBOLT_COMPONENT" > /etc/apt/sources.list.d/passbolt.list \ + && apt-get update \ + && DEBIAN_FRONTEND=non-interactive apt-get -y install --no-install-recommends \ + nginx \ + $PASSBOLT_PKG \ + supervisor \ + curl \ + && rm -f /etc/passbolt/jwt/* \ + && rm /etc/nginx/sites-enabled/default \ + && mkdir /run/php \ + && cp /usr/share/passbolt/examples/nginx-passbolt-ssl.conf /etc/nginx/snippets/passbolt-ssl.conf \ + && sed -i 's,;clear_env = no,clear_env = no,' /etc/php/$PHP_VERSION/fpm/pool.d/www.conf \ + && sed -i 's,# include __PASSBOLT_SSL__,include /etc/nginx/snippets/passbolt-ssl.conf;,' /etc/nginx/sites-enabled/nginx-passbolt.conf \ + && sed -i '/listen \[\:\:\]\:443 ssl http2;/a listen 443 ssl http2;' /etc/nginx/snippets/passbolt-ssl.conf \ + && sed -i 's,__CERT_PATH__,/etc/ssl/certs/certificate.crt;,' /etc/nginx/snippets/passbolt-ssl.conf \ + && sed -i 's,__KEY_PATH__,/etc/ssl/certs/certificate.key;,' /etc/nginx/snippets/passbolt-ssl.conf \ + && sed -i 's,www-data.*$,root su -s /bin/bash -c ". /etc/environment \&\& $PASSBOLT_BASE_DIR/bin/cron" www-data >/proc/1/fd/1 2>\&1,' /etc/cron.d/$PASSBOLT_PKG \ + && sed -i 's/# server_tokens/server_tokens/' /etc/nginx/nginx.conf \ + && ln -sf /dev/stdout /var/log/nginx/passbolt-access.log \ + && ln -sf /dev/stderr /var/log/nginx/passbolt-error.log \ + && ln -sf /dev/stderr /var/log/passbolt/error.log \ + && ln -sf /dev/stderr /var/log/php$PHP_VERSION-fpm.log COPY conf/supervisor/cron.conf /etc/supervisor/conf.d/cron.conf COPY conf/supervisor/nginx.conf /etc/supervisor/conf.d/nginx.conf @@ -52,6 +52,13 @@ COPY scripts/entrypoint/passbolt/deprecated_paths.sh /passbolt/deprecated_paths. COPY scripts/entrypoint/passbolt/entropy.sh /passbolt/entropy.sh COPY scripts/wait-for.sh /usr/bin/wait-for.sh +# Docker API does not support buildkit so we +# need to do this workaround https://github.com/docker/for-linux/issues/1136 +RUN chmod 0644 /etc/supervisor/conf.d/* \ + && chmod 0700 /docker-entrypoint.sh \ + && chmod 0700 /passbolt/* \ + && chmod 0700 /usr/bin/wait-for.sh + EXPOSE 80 443 WORKDIR /usr/share/php/passbolt diff --git a/debian/Dockerfile.rootless b/debian/Dockerfile.rootless index 39b5434..6ba8bd6 100644 --- a/debian/Dockerfile.rootless +++ b/debian/Dockerfile.rootless @@ -40,6 +40,8 @@ RUN apt-get update \ && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic COPY conf/supervisor/cron.conf.rootless /etc/supervisor/conf.d/cron.conf +COPY conf/supervisor/nginx.conf /etc/supervisor/conf.d/nginx.conf +COPY conf/supervisor/php.conf /etc/supervisor/conf.d/php.conf RUN sed -i 's,listen 80;,listen 8080;,' /etc/nginx/sites-enabled/nginx-passbolt.conf \ && sed -i 's,listen \[\:\:\]\:80;,listen \[\:\:\]\:8080;,' /etc/nginx/sites-enabled/nginx-passbolt.conf \ @@ -67,6 +69,9 @@ RUN sed -i 's,listen 80;,listen 8080;,' /etc/nginx/sites-enabled/nginx-passbolt. && chown www-data:0 /etc/passbolt/certs \ && chown www-data:0 /etc/passbolt/jwt \ && chown www-data:0 /var/log/supervisor \ + && chown www-data:0 /etc/supervisor/conf.d/cron.conf \ + && chown www-data:0 /etc/supervisor/conf.d/php.conf \ + && chown www-data:0 /etc/supervisor/conf.d/nginx.conf \ && chown -R www-data:0 /var/log/nginx \ && ln -sf /dev/stdout /var/log/nginx/passbolt-access.log \ && ln -sf /dev/stderr /var/log/nginx/passbolt-error.log \ @@ -81,8 +86,6 @@ RUN sed -i 's,listen 80;,listen 8080;,' /etc/nginx/sites-enabled/nginx-passbolt. && chown www-data:www-data /etc/environment \ && chmod 600 /etc/environment -COPY conf/supervisor/nginx.conf /etc/supervisor/conf.d/nginx.conf -COPY conf/supervisor/php.conf /etc/supervisor/conf.d/php.conf COPY scripts/entrypoint/docker-entrypoint.rootless.sh /docker-entrypoint.sh COPY scripts/entrypoint/passbolt/entrypoint-rootless.sh /passbolt/entrypoint-rootless.sh COPY scripts/entrypoint/passbolt/env.sh /passbolt/env.sh @@ -90,6 +93,13 @@ COPY scripts/entrypoint/passbolt/deprecated_paths.sh /passbolt/deprecated_paths. COPY scripts/entrypoint/passbolt/entropy.sh /passbolt/entropy.sh COPY scripts/wait-for.sh /usr/bin/wait-for.sh +# Docker API does not support buildkit so we +# need to do this workaround https://github.com/docker/for-linux/issues/1136 +RUN chmod 0644 /etc/supervisor/conf.d/* \ + && chmod 0755 /docker-entrypoint.sh \ + && chmod 0755 /passbolt/* \ + && chmod 0755 /usr/bin/wait-for.sh + EXPOSE 8080 4433 WORKDIR /usr/share/php/passbolt diff --git a/spec/docker_image/image_spec.rb b/spec/docker_image/image_spec.rb index 9af6eb6..1863a95 100644 --- a/spec/docker_image/image_spec.rb +++ b/spec/docker_image/image_spec.rb @@ -2,14 +2,13 @@ require 'json' describe 'Dockerfile' do - before(:all) do set :env, { - 'DATASOURCES_DEFAULT_HOST' => '172.17.0.2', + 'DATASOURCES_DEFAULT_HOST' => '172.17.0.2', 'DATASOURCES_DEFAULT_PASSWORD' => 'P4ssb0lt', 'DATASOURCES_DEFAULT_USERNAME' => 'passbolt', 'DATASOURCES_DEFAULT_DATABASE' => 'passbolt', - 'PASSBOLT_GPG_KEYRING' => '/var/lib/passbolt/.gnupg' + 'PASSBOLT_GPG_KEYRING' => '/var/lib/passbolt/.gnupg' } if ENV['GITLAB_CI'] @@ -18,13 +17,19 @@ 'password' => ENV['CI_REGISTRY_PASSWORD'].to_s, 'serveraddress' => 'https://registry.gitlab.com/' ) - if ENV['ROOTLESS'] == 'true' - @image = Docker::Image.create('fromImage' => "#{ENV['CI_REGISTRY_IMAGE']}:#{ENV['PASSBOLT_FLAVOUR']}-rootless-latest") - else - @image = Docker::Image.create('fromImage' => "#{ENV['CI_REGISTRY_IMAGE']}:#{ENV['PASSBOLT_FLAVOUR']}-root-latest") - end + @image = if ENV['ROOTLESS'] == 'true' + Docker::Image.create('fromImage' => "#{ENV['CI_REGISTRY_IMAGE']}:#{ENV['PASSBOLT_FLAVOUR']}-rootless-latest") + else + Docker::Image.create('fromImage' => "#{ENV['CI_REGISTRY_IMAGE']}:#{ENV['PASSBOLT_FLAVOUR']}-root-latest") + end else - @image = Docker::Image.build_from_dir(ROOT_DOCKERFILES, { 'dockerfile' => $dockerfile, 'buildargs' => JSON.generate($buildargs) } ) + @image = Docker::Image.build_from_dir( + ROOT_DOCKERFILES, + { + 'dockerfile' => $dockerfile, + 'buildargs' => JSON.generate($buildargs) + } + ) end set :docker_image, @image.id set :docker_container_create_options, { 'Cmd' => '/bin/sh' } @@ -34,22 +39,24 @@ let(:php_conf) { '/etc/php/7.4/fpm/php.ini' } let(:site_conf) { '/etc/nginx/sites-enabled/nginx-passbolt.conf' } let(:supervisor_conf) do - [ '/etc/supervisor/conf.d/nginx.conf', - '/etc/supervisor/conf.d/php.conf', - '/etc/supervisor/conf.d/cron.conf' ] + ['/etc/supervisor/conf.d/nginx.conf', + '/etc/supervisor/conf.d/php.conf', + '/etc/supervisor/conf.d/cron.conf'] end let(:passbolt_home) { '/usr/share/php/passbolt' } let(:passbolt_tmp) { '/var/lib/passbolt/tmp' } let(:passbolt_image) { "#{passbolt_home}/webroot/img/public" } let(:passbolt_owner) { 'www-data' } - let(:exposed_ports) { [ $http_port, $https_port ] } - let(:php_extensions) { [ - 'gd', 'intl', 'json', 'mysqlnd', 'xsl', 'phar', - 'posix', 'xml', 'zlib', 'ctype', 'pdo', 'gnupg', 'pdo_mysql' - ] } + let(:exposed_ports) { [$http_port, $https_port] } + let(:php_extensions) do + %w[ + gd intl json mysqlnd xsl phar + posix xml zlib ctype pdo gnupg pdo_mysql + ] + end let(:wait_for) { '/usr/bin/wait-for.sh' } - jwt_conf = "#{PASSBOLT_CONFIG_PATH + '/jwt'}" - let(:jwt_key_pair) { [ "#{jwt_conf}/jwt.key", "#{jwt_conf}/jwt.pem" ] } + let(:jwt_conf) { "#{PASSBOLT_CONFIG_PATH + '/jwt'}" } + let(:jwt_key_pair) { ["#{jwt_conf}/jwt.key", "#{jwt_conf}/jwt.pem"] } describe 'passbolt required php extensions' do it 'has php extensions installed' do @@ -67,6 +74,14 @@ it 'has config files' do supervisor_conf.each do |config| expect(file(config)).to exist + if ENV['ROOTLESS'] == 'true' + expect(file(config)).to be_owned_by(passbolt_owner) + else + expect(file(config)).to be_owned_by('root') + end + expect(file(config)).to be_writable.by('owner') + expect(file(config)).not_to be_writable.by('group') + expect(file(config)).not_to be_writable.by('others') end end end @@ -159,18 +174,25 @@ end end - describe file(jwt_conf) do - it { should be_a_directory } - it { should be_mode 770 } - it { should be_owned_by($root_user) } - it { should be_grouped_into($config_group) } - end + describe 'jwt configuration' do + it 'should have the correct permissions' do + expect(file(jwt_conf)).to be_a_directory + expect(file(jwt_conf)).to be_mode 770 + expect(file(jwt_conf)).to be_owned_by($root_user) + expect(file(jwt_conf)).to be_grouped_into($config_group) + end - describe file("#{jwt_conf}/jwt.key") do - it { should_not exist } - end - describe file("#{jwt_conf}/jwt.pem") do - it { should_not exist } + describe 'JWT key file' do + it 'should not exist' do + expect(file("#{jwt_conf}/jwt.key")).not_to exist + end + end + + describe 'JWT pem file' do + it 'should not exist' do + expect(file("#{jwt_conf}/jwt.pem")).not_to exist + end + end end describe '/etc/environment' do @@ -178,17 +200,17 @@ expect(file('/etc/environment')).to exist if ENV['ROOTLESS'] == 'true' expect(file('/etc/environment')).to be_owned_by(passbolt_owner) - expect(file('/etc/environment')).to be_mode 600 + expect(file('/etc/environment')).to be_mode 600 else expect(file('/etc/environment')).to be_owned_by($root_user) - expect(file('/etc/environment')).to be_mode 644 + expect(file('/etc/environment')).to be_mode 644 end end end describe 'cron table' do it 'exists and executes the email job' do - expect(cron.table).to match(/PASSBOLT_BASE_DIR\/bin\/cron/) + expect(cron.table).to match(%r{PASSBOLT_BASE_DIR/bin/cron}) end end end diff --git a/spec/docker_runtime/runtime_spec.rb b/spec/docker_runtime/runtime_spec.rb index 420b55b..6935b14 100644 --- a/spec/docker_runtime/runtime_spec.rb +++ b/spec/docker_runtime/runtime_spec.rb @@ -100,7 +100,7 @@ ) @container.exec(['cp', '/tmp/passbolt-cron-temporary', "/etc/cron.d/passbolt-#{ENV['PASSBOLT_FLAVOUR']}-server"]) # force reload supercronic cron file - @container.exec(['supervisorctl', 'restart', 'cron']) + @container.exec(%w[supervisorctl restart cron]) # wait for cron sleep 61