diff --git a/manifests/run.pp b/manifests/run.pp index db0b3f20..e9599931 100644 --- a/manifests/run.pp +++ b/manifests/run.pp @@ -20,6 +20,12 @@ # This will allow the docker container to be restarted if it dies, without # puppet help. # +# @param verify_digest +# (optional) Make sure, that the image has not modified. Compares the digest +# checksum before starting the docker image. +# To get the digest of an image, run the following command: +# docker image inspect <> --format='{{index .RepoDigests 0}} +# # @param service_prefix # (optional) The name to prefix the startup script with and the Puppet # service resource title with. Default: 'docker-' @@ -186,6 +192,7 @@ define docker::run( Optional[Pattern[/^[\S]*$/]] $image, Optional[Enum[present,absent]] $ensure = 'present', + Optional[String] $verify_digest = undef, Optional[String] $command = undef, Optional[Pattern[/^[\d]*(b|k|m|g)$/]] $memory_limit = '0b', Variant[String,Array,Undef] $cpuset = [], diff --git a/spec/acceptance/docker_full_spec.rb b/spec/acceptance/docker_full_spec.rb index d435b7bd..0021cb0a 100644 --- a/spec/acceptance/docker_full_spec.rb +++ b/spec/acceptance/docker_full_spec.rb @@ -9,6 +9,7 @@ 'nanoserver-sac2016' end default_digest = 'sha256:dcba85354678b50608b8c40ec6d17cce063a224aa0e12b6a55dc47b67f039e75' + default_local_digest = 'sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10' second_image = 'winamd64/hola-mundo' default_dockerfile = 'C:/Users/Administrator/AppData/Local/Temp/Dockerfile' dockerfile_test = 'C:/Windows/Dockerfile_test.txt' @@ -34,6 +35,7 @@ second_image = 'busybox' default_image_tag = '3.7' default_digest = 'sha256:3dcdb92d7432d56604d4545cbd324b14e647b313626d99b889d0626de158f73a' + default_local_digest = 'sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10' default_dockerfile = '/root/Dockerfile' dockerfile_test = "#{default_dockerfile}_test.txt" docker_command = 'docker' @@ -833,6 +835,35 @@ class { 'docker': #{docker_args} } apply_manifest(pp_delete, catch_failures: true) end end + + it 'run with verify_digest' do + pp = <<-EOS + class { 'docker': #{docker_args} } + docker::image { '#{default_image}:#{default_image_tag}': + require => Class['docker'], + } + docker::run { '#{default_image}': + image => '#{default_image}:#{default_image_tag}', + verify_digest => '#{default_local_digest}', + } + EOS + pp_invalid = <<-EOS + docker::run { '#{default_image}': + image => '#{default_image}:#{default_image_tag}', + verify_digest => 'sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc000', + } + EOS + + apply_manifest(pp, catch_failures: true) + run_shell('/usr/local/bin/docker-run-alpine-start.sh', expect_failures: false) do |r| + expect(r.stdout.include?('Digest verify failed!')).to be false + end + + apply_manifest(pp_invalid, catch_failures: true) + run_shell('/usr/local/bin/docker-run-alpine-start.sh', expect_failures: true) do |r| + expect(r.stdout.include?('Digest verify failed!')).to be true + end + end end describe 'docker::exec', win_broken: true do diff --git a/templates/docker-run-start.erb b/templates/docker-run-start.erb index ceda9f57..b1aecba1 100644 --- a/templates/docker-run-start.erb +++ b/templates/docker-run-start.erb @@ -9,6 +9,15 @@ /usr/bin/<%= @docker_command %> pull <%= @image %> <% end -%> +<% if @verify_digest -%> + digest_local=$(docker image inspect <%= @image %> --format='{{index .RepoDigests 0}}') + digest_verify="<%= @verify_digest %>" + if [ "${digest_local##*:}" != "${digest_verify##*:}" ]; then + echo "Digest verify failed! Expected checksum 'sha256:$digest_verify' does not match with local checksum 'sha256:$digest_local'!" + exit 2 + fi +<% end -%> + /usr/bin/<%= @docker_command %> create \ <%= @docker_run_flags %> \ --name <%= @sanitised_title %> \