From 04614ec67acc21182b65e0ef0c2e06794418e7aa Mon Sep 17 00:00:00 2001 From: Zen-Fu <zen@systemli.org> Date: Tue, 8 Apr 2025 10:41:19 -0300 Subject: [PATCH] remove the puppet profile As a step to migrate to g10k, we need the puppet profile to live in the main Puppet control repository, so we just wipe it from here. See: https://gitlab.tails.boum.org/tails/puppet-code/-/merge_requests/18 refs tpo/tpa/team#42095 --- .../puppet/master/check-commit-signature | 313 ------------------ files/profile/puppet/master/gitlab-mirror | 6 - files/profile/puppet/master/logrotate.conf | 13 - .../parser/functions/tails_read_file.rb | 12 - manifests/profile/puppet/agent.pp | 22 -- manifests/profile/puppet/enc.pp | 73 ---- manifests/profile/puppet/eyaml.pp | 24 -- manifests/profile/puppet/master.pp | 137 -------- manifests/profile/puppet/masterless.pp | 51 --- manifests/profile/puppet/oneshot.pp | 37 --- 10 files changed, 688 deletions(-) delete mode 100755 files/profile/puppet/master/check-commit-signature delete mode 100755 files/profile/puppet/master/gitlab-mirror delete mode 100644 files/profile/puppet/master/logrotate.conf delete mode 100644 lib/puppet/parser/functions/tails_read_file.rb delete mode 100644 manifests/profile/puppet/agent.pp delete mode 100644 manifests/profile/puppet/enc.pp delete mode 100644 manifests/profile/puppet/eyaml.pp delete mode 100644 manifests/profile/puppet/master.pp delete mode 100644 manifests/profile/puppet/masterless.pp delete mode 100644 manifests/profile/puppet/oneshot.pp diff --git a/files/profile/puppet/master/check-commit-signature b/files/profile/puppet/master/check-commit-signature deleted file mode 100755 index 818664a55..000000000 --- a/files/profile/puppet/master/check-commit-signature +++ /dev/null @@ -1,313 +0,0 @@ -#!/usr/bin/env bash -############################################################################## -# -# check-commit-signature -# ---------------------- -# A server-side update git hook for checking the GPG signature of a pushed -# commit. -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunsignedcommits -# This boolean sets whether unsigned tags, and merges with unsigned commits -# into master, are allowed. By default, they are not allowed. -# hooks.allowunsignedtags -# This boolean sets whether unsigned tags are allowed. By default, -# they are not allowed. -# hooks.allowunverifiedsigs -# This boolean sets whether commits/tags signed by -# unverified/untrusted keys are allowed. By default, they are not allowed. -# hooks.allowcommitsonmaster -# This boolean sets whether non-merge commits are allowed on master. By -# default, these are not allowed. -# hooks.allowhotfixonmaster -# The boolean sets whether branches beginning with hotfix-* are allowed on -# master. NOT YET IMPLEMENTED. CURRENTLY IGNORED. -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# hooks.restrictmergetomaster -# This boolean sets whether restrictions on merging to master should be -# enforced. By default there won't be. -# -# @author Isis Agora Lovecruft, 0x2cdb8b35, simplified by groente@puscii.nl -# @date 30 June 2023 -# @version 0.0.2 -############################################################################## - -## $1 is the git ref which is being revised -## $2 is the last HEAD -## $3 is the HEAD commit of the series of commits being applied -ref=$1 -rev_old=$2 -rev_new=$3 - -allowunsignedcommits=false -allowunsignedtags=false -allowunverifiedsigs=false -allowcommitsonmaster=true -allowhotfixonmaster=true -allowdeletebranch=true -denycreatebranch=false -allowunannotated=false -allowdeletetag=false -allowmodifytag=false -restrictmergetomaster=false - -## the following is the short reference name for tags, i.e. 'v0.1.2' in -## lieu of 'refs/tags/v0.1.2': -short_ref=${ref##refs/tags/} - -## a hash full of zeroes is how Git represents "nothing" -zero="0000000000000000000000000000000000000000" - -## get all new commits on branch ref, even if it's a new branch -if [ "$rev_old" = "$zero" ]; then - # list everything reachable from rev_new but not any heads - span=$(git rev-list $rev_new --not --branches='*') -elif [ "$rev_new" = "$zero" ]; then - # when deleting a branch there are no new commits - span='' -else - span=$(git rev-list ^$rev_old $rev_new) -fi - -if [ "$allowcommitsonmaster" != "true" ]; then - ## the only commits allowed on master are merges which have rev_old as - ## a direct parent of rev_new - ## - ## we have to check this in a separate step, since "git rev-list - ## ^rev_old rev_new" on master at the merge of a feature branch will - ## also give us all the commits on the feature branch, and we won't - ## have enough context while looping through those commits to do this - ## check properly - if [ "$ref" = "refs/heads/master" ]; then - ## if rev_new isn't a merge, it will only have one parent and - ## this "git show" command will return nothing - parents=$(git show --merges --no-patch --format=%P $rev_new) - old_is_parent_of_new=false - for parent in $parents ; do - if [ "$rev_old" = "$parent" ]; then - old_is_parent_of_new=true - break - fi - done - - if [ "$old_is_parent_of_new" != "true" ]; then - echo "*** Master only accepts merges of feature branches" >&2 - exit 1 - fi - fi -fi - -if [ -z "$span" ]; then - if [ "$rev_new" = "$zero" ]; then - type=delete - else - ## rev_new pointed to something considered by "git rev-list" to be - ## already in the commit graph, which could be a commit (if we're - ## adding a lightweight tag) or a tag object (if we're adding an - ## annotated tag), since "git rev-list" doesn't consider the tag - ## object to be separate from the commit it points to - type=$(git cat-file -t $rev_new) - fi - - case $type in - commit) - ## lightweight tag - if [ "$allowunsignedtags" != "true" -o "$allowunannotated" != "true" ]; then - echo "*** The un-annotated tag $short_ref is not allowed in this repository" >&2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - tag) - ## annotated tag - if [ "$rev_old" != $zero -a "$allowmodifytag" != "true" ]; then - echo "*** Tag $short_ref already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - else - if [ "$allowunsignedtags" != "true" ]; then - result=$(git verify-tag $rev_new 2>&1 >/dev/null) - if ! grep '^gpg: Good signature' <<< "$result"; then - echo "*** Tag $short_ref is not signed" >&2w - exit 1 - fi - fi - fi - ;; - delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting branches is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - echo "*** No new commits, but the pushed ref $ref is a \"$type\" instead of a tag? I'm confused." >&2 - exit 1 - ;; - esac -fi - -## for all the commits in the series, check the type of the commit against the -## commit directly before it: -rev_cur=$rev_old ## set the current rev to the previous HEAD -for commit in $span ; do - - ## check that the current revison object is a hexidecimal hash of length 40 - check_rev=$(git rev-parse --verify "$commit") - if ! grep -q -E '^[0-9A-Fa-f]{40}$' <<< $check_rev; then - echo "*** Commit hash is not 40 hex characters" >&2 - exit 1 - fi - - ## get the commit type of the current rev: - ## a commit with a hash full of zeros is a deletion of a ref - if [ "$commit" = "$zero" ]; then - commit_type=delete - else - if [ "$rev_cur" = "$zero" ]; then - ## there was no previous commit to check against, - ## so this is the first commit on a branch - commit_type=$(git cat-file -t "$commit") - else - merge=$(git rev-list -n 1 --merges "$rev_cur".."$commit") - if test -n "$merge"; then - commit_type=merge - else - commit_type=$(git cat-file -t "$commit") - fi - fi - fi - - ## the following returns non-null if $rev_cur is originating from branches - ## beginning with the name "devel": - is_from_develop=$(git branch --contains "$commit" | grep devel ) - - ## the following returns non-null if $rev_cur is originating from branches - ## beginning with the name "release": - is_from_release=$(git branch --contains "$commit" | grep release ) - - ## the following returns non-null if $rev_cur is a signed tag: - is_signed_tag=$(git tag --verify "$ref" 2>&1 >/dev/null | grep '^gpg:') - - ## the following returns non-null if $rev_cur has a signature, and gpg reports - ## the signature is good: - verify_sig=$(git verify-commit --raw "$commit" 2>&1) - has_good_sig=$? - if [ $has_good_sig -eq 0 ] && [ "$allowunverifiedsigs" != "true" ]; then - has_verified_sig=false - echo "$verify_sig" | grep -e '^\[GNUPG:\] TRUST_UNDEFINED' >/dev/null || has_verified_sig=true - fi - - ## the following extracts the signing keyid (either short or long) from the - ## signature on $rev_cur: - signing_keyid=$(git show --no-patch --format=%H --show-signature "$commit" | \ - grep -oE "^gpg:\s+ using .* key [0-9A-Fa-f]{16}" | \ - sed -e 's/^.* \([0-9A-Fa-f]\{16\}$\)/\1/' ) - fpr_signing_keyid=$(gpg --fingerprint "$signing_keyid" 2>/dev/null | \ - grep -o -E "([0-9A-F]{4}[[:space:]]{0,2}){10}") - - case "$ref","$commit_type" in - refs/heads/*,commit) - ## commit on any branch - if [ "$rev_old" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - - if [ "$allowunsignedcommits" != "true" ]; then - if [ "$has_good_sig" -ne 0 ]; then - echo "*** Bad signature on commit $commit" >&2 - exit 1 - fi - - if [ "$allowunverifiedsigs" != "true" ] && [ "$has_verified_sig" != "true" ]; then - echo "has_verified_sig $has_verified_sig" - echo "*** Unverified signature on commit $commit" >&2 - exit 1 - fi - fi - ;; - refs/heads/master,merge) - ## only allow merges to master from release-* and develop/* - if [ "$restrictmergetomaster" = "true" ] && test -z "$is_from_develop" -a -z "$is_from_release"; then - echo "*** Branch master only takes merge commits originating from develop/* or release-* branches" >&2 - exit 1 - else - if [ "$allowunsignedcommits" != "true" ]; then - if [ -n "$has_good_sig" -a -n "$signing_keyid" ]; then - echo "all good!" - else - echo "*** Merges must be signed with an authorised key" >&2 - exit 1 - fi - fi - fi - ;; - refs/heads/*,merge) - ## merge into non-master branch - if [ "$allowunsignedcommits" != "true" ]; then - if [ -n "$has_good_sig" -a -n "$signing_keyid" ]; then - echo "all good!" - else - echo "*** Merges must be signed with an authorised key" >&2 - exit 1 - fi - fi - ;; - refs/heads/master,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting master is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/master,*) - ## kill it with fire - echo "*** Branch master only takes merge commits originating from develop/* or release-* branches" >&2 - exit 1 - ;; - refs/tags/*,delete) - ## delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - ## tracking branch - ;; - refs/remotes/*,delete) - ## delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - ## Anything else (is there anything else?) - echo "*** Unknown type of update to ref $ref of type $commit_type " >&2 - exit 1 - ;; - esac - ## increment the current rev to the $commit we just checked: - rev_cur=$commit -done - diff --git a/files/profile/puppet/master/gitlab-mirror b/files/profile/puppet/master/gitlab-mirror deleted file mode 100755 index 4d3c3b399..000000000 --- a/files/profile/puppet/master/gitlab-mirror +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -set -eu - -/usr/bin/git push --quiet --all --force --prune mirror -/usr/bin/git push --quiet --tags --force mirror diff --git a/files/profile/puppet/master/logrotate.conf b/files/profile/puppet/master/logrotate.conf deleted file mode 100644 index ae45cf1d3..000000000 --- a/files/profile/puppet/master/logrotate.conf +++ /dev/null @@ -1,13 +0,0 @@ -# Keep 12 weeks of logs, rotate once a week -/var/log/puppet/masterhttp.log { - weekly - missingok - rotate 12 - compress - delaycompress - notifempty - # Puppet 5 doesn't have "reload", so we restart it instead - postrotate - /bin/systemctl restart puppetserver - endscript -} diff --git a/lib/puppet/parser/functions/tails_read_file.rb b/lib/puppet/parser/functions/tails_read_file.rb deleted file mode 100644 index 3e773260b..000000000 --- a/lib/puppet/parser/functions/tails_read_file.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'yaml' - -module Puppet::Parser::Functions - newfunction(:tails_read_file, type: :rvalue) do |args| - file = args[0] - begin - File.open(file).read - rescue Errno::ENOENT, Errno::EACCES - '' - end - end -end diff --git a/manifests/profile/puppet/agent.pp b/manifests/profile/puppet/agent.pp deleted file mode 100644 index 19c46cc80..000000000 --- a/manifests/profile/puppet/agent.pp +++ /dev/null @@ -1,22 +0,0 @@ -# @summary -# profile for puppet agents -# -class tails::profile::puppet::agent { - class { 'puppet': - runmode => 'systemd.timer', - systemd_randomizeddelaysec => 25 * 60, - manage_packages => false, - agent => true, - ssldir => '/var/lib/puppet/ssl', - vardir => '/var/cache/puppet', - sharedir => '/usr/share/puppet', - additional_settings => { fact_value_length_soft_limit => 65535 }, - } - - file { '/opt/puppetlabs': - ensure => directory, - owner => 'root', - group => 'root', - mode => '0755', - } -} diff --git a/manifests/profile/puppet/enc.pp b/manifests/profile/puppet/enc.pp deleted file mode 100644 index 753002174..000000000 --- a/manifests/profile/puppet/enc.pp +++ /dev/null @@ -1,73 +0,0 @@ -# @summary -# The following Puppet ENC was added to help with more complex deployments, -# but is (currently) not really needed/used during normal operation. If you -# want to remove it, please make sure to check the contents of the script in -# case its use has changed and this comment has not been updated. -# -class tails::profile::puppet::enc () { - # lint:ignore:strict_indent - $_script = @(EOT) - #!/usr/bin/python3 - # - # This is a simple Puppet ENC aimed to help with complex deployments. It allows - # nodes to be mapped to different Puppet environments which, in our case, map - # to different Git branches of our Puppet code repository. - # - # The script takes a node name as its only argument and prints a YAML document - # containing an `environment` key whose content depends on the node. - # - # By default, nodes not explicitly listed in the ENVIRONMENTS dict will be - # mapped to the `production` environment. - # - # To assign a node to a different environment, add it to the ENVIRONMENTS dict, - # as such: - # - # ENVIRONMENTS = defaultdict(lambda: 'production', { - # 'dev-node.example.com': 'development', - # 'special-node.example.com': 'special-branch', - # } - # - # No classes or parameters are currently set by this script, even though their - # corresponding keys are included in the output YAML file, as containing at - # least one of them is a requirement according to the ENC specs. - # - # Make sure to push the corresponding branch(es) to the Puppet code repository - # before pushing new node-to-env mappings in this script, otherwise Puppet - # apply will fail in those nodes as the Puppet Server won't be able to find the - # corresponding branch(es) in the repository. - # - # References: - # - # https://www.puppet.com/docs/puppet/latest/nodes_external.html - # https://github.com/theforeman/puppet-puppet#git-repo-support - - from argparse import ArgumentParser - from collections import defaultdict - - - ENVIRONMENTS = defaultdict(lambda: 'production', {}) - - - def parse_args(): - parser = ArgumentParser() - parser.add_argument('node', help='The node to be classified.') - return parser.parse_args() - - - if __name__ == '__main__': - args = parse_args() - env = ENVIRONMENTS[args.node] - print('classes: {}') - print('parameters: {}') - print(f'environment: {env}') - | EOT - # lint:endignore - - file { '/usr/local/bin/puppet-enc': - ensure => 'file', - content => $_script, - mode => '0755', - owner => 'root', - group => 'root', - } -} diff --git a/manifests/profile/puppet/eyaml.pp b/manifests/profile/puppet/eyaml.pp deleted file mode 100644 index 33c458292..000000000 --- a/manifests/profile/puppet/eyaml.pp +++ /dev/null @@ -1,24 +0,0 @@ -# @summary -# profile to ensure a node has hiera-eyaml installed and keys generated -# -# @param puppetuser -# the posix user that should generate and own the eyaml keys -# -class tails::profile::puppet::eyaml ( - String $puppetuser = 'puppet', -) { - ensure_packages(['hiera-eyaml']) - - file { '/etc/puppet/keys': - ensure => directory, - mode => '0755', - owner => $puppetuser, - } - - exec { '/usr/bin/eyaml createkeys --pkcs7-keysize=4096': - user => $puppetuser, - cwd => '/etc/puppet', - creates => '/etc/puppet/keys/private_key.pkcs7.pem', - require => [File['/etc/puppet/keys'], Package['hiera-eyaml']], - } -} diff --git a/manifests/profile/puppet/master.pp b/manifests/profile/puppet/master.pp deleted file mode 100644 index cfd7e767a..000000000 --- a/manifests/profile/puppet/master.pp +++ /dev/null @@ -1,137 +0,0 @@ -# @summary -# profile for puppetmaster -# -# @param external_nodes -# external nodes classifier executable -# -# @param public_mirror -# where to sync the code repository to -# -class tails::profile::puppet::master ( - Variant[String[0], Stdlib::Absolutepath] $external_nodes = undef, - String $public_mirror = 'git@gitlab-ssh.tails.boum.org:tails/puppet-code', -) { - include rbac - - file { [ - '/opt', - '/opt/puppetlabs', - '/opt/puppetlabs/server', - '/opt/puppetlabs/server/apps', - '/opt/puppetlabs/server/apps/puppetserver', - '/etc/puppet/conf.d', - ]: - ensure => directory, - } - -# dirty hack to prevent the puppetmodule from resetting vardir ownership -# and restarting puppet master all the time - File <| title == '/var/lib/puppet' |> { - owner => undef, - group => undef, - } - File <| title == '/var/cache/puppet' |> { - owner => undef, - group => undef, - } - - class { 'puppet': - manage_packages => true, - agent => true, - runmode => 'systemd.timer', - server => true, - server_reports => 'store,puppetdb', - server_foreman => false, - server_external_nodes => $external_nodes, - server_git_repo => true, - server_git_repo_path => '/var/lib/puppet/puppet-code.git', - server_storeconfigs => true, - additional_settings => { fact_value_length_soft_limit => 65535 }, - } - - class { 'puppet::server::puppetdb': - server => $facts['networking']['fqdn'], - } - -# ensure all commits to our puppet repo are signed - - file { '/var/lib/puppet/puppet-code.git/hooks/update': - source => 'puppet:///modules/tails/profile/puppet/master/check-commit-signature', - owner => 'puppet', - group => 'puppet', - mode => '0755', - require => Class['puppet'], - } - -# ensure we have a remote for our public mirror - - exec { "/usr/bin/git -C /var/lib/puppet/puppet-code.git remote add mirror ${public_mirror}": - user => puppet, - group => puppet, - unless => '/usr/bin/git -C /var/lib/puppet/puppet-code.git remote |grep -qs -x mirror'; - } - -# and set up a hook to sync to the public mirror - - file { '/var/lib/puppet/puppet-code.git/hooks/post-update': - source => 'puppet:///modules/tails/profile/puppet/master/gitlab-mirror', - owner => 'puppet', - group => 'puppet', - mode => '0755', - require => Class['puppet'], - } -# ensure we have backups for the puppetdb - - include backupninja - backupninja::pgsql { 'backup-puppetdb': - ensure => present, - } - -# make sure we can encrypt sensitive data in hiera - - include tails::profile::puppet::eyaml - -# ensure sysadmins can access the git repo - - rbac::ssh { 'sysadmins-to-puppet': - user => 'puppet', - role => 'sysadmins', - } - -# ensure puppet knows the sysadmin PGP keys - - include yapgp - $rbac::roles['sysadmins'].each | String $username | { - $fp = $rbac::users[$username]['pgpkey'] - - pgp_key { "puppet-${fp}": - ensure => present, - fp => $fp, - user => puppet, - trust => 5, - } - } - -# Clean up reports - - exec { '/usr/bin/find /var/lib/puppetserver/reports -type f -ctime +2 -exec /bin/rm {} \;': } - -# Firewall - - tirewall::accept_trusted_subnets { 'Puppet Master': - dport => 8140, - } - -# Log rotation - - ensure_packages(['logrotate']) - - file { '/etc/logrotate.d/puppet': - ensure => file, - owner => root, - group => root, - mode => '0644', - source => 'puppet:///modules/tails/profile/puppet/master/logrotate.conf', - require => Package['logrotate'], - } -} diff --git a/manifests/profile/puppet/masterless.pp b/manifests/profile/puppet/masterless.pp deleted file mode 100644 index 4148f9586..000000000 --- a/manifests/profile/puppet/masterless.pp +++ /dev/null @@ -1,51 +0,0 @@ -# masterless puppet run -# -# assumes this repo is already cloned in /etc/puppet/code -# -class tails::profile::puppet::masterless { - ensure_packages(['puppet']) - - include tails::profile::puppet::eyaml - - file { '/etc/puppet/hiera.yaml': - ensure => symlink, - target => '/etc/puppet/code/hiera.yaml', - } - - # lint:ignore:strict_indent - $_service = @(EOT) - [Unit] - Description=Timer for masterless puppet runs - - [Service] - Type=oneshot - User=root - Group=root - ExecStartPre=-find /var/cache/puppet/reports -type f -ctime +1 -exec rm -f {} \; - ExecStartPre=-/usr/bin/git -C /etc/puppet/code pull --ff-only --verify-signatures - ExecStartPre=-/usr/bin/git -C /etc/puppet/code submodule sync - ExecStartPre=-/usr/bin/git -C /etc/puppet/code submodule update --init --recursive - ExecStart=/usr/bin/puppet apply /etc/puppet/code/manifests/%H.pp - | EOT - - $_timer = @(EOT) - [Unit] - Description=Timer for masterless puppet runs - - [Timer] - OnCalendar=*-*-* *:05,35:00 - Persistent=true - RandomizedDelaySec=1500 - - [Install] - WantedBy=timers.target - | EOT - # lint:endignore - - systemd::timer { 'run-puppet.timer': - timer_content => $_timer, - service_content => $_service, - active => true, - enable => true, - } -} diff --git a/manifests/profile/puppet/oneshot.pp b/manifests/profile/puppet/oneshot.pp deleted file mode 100644 index 92a386813..000000000 --- a/manifests/profile/puppet/oneshot.pp +++ /dev/null @@ -1,37 +0,0 @@ -# @summary -# oneshot puppet run -# -class tails::profile::puppet::oneshot { - class { 'puppet': - runmode => 'unmanaged', - manage_packages => false, - agent => true, - ssldir => '/var/lib/puppet/ssl', - vardir => '/var/cache/puppet', - sharedir => '/usr/share/puppet', - } - - systemd::unit_file { 'puppet-oneshot.service': - enable => true, - content => '[Unit] -Description=Service to run puppet agent once -After=network.target - -[Service] -Type=oneshot -ExecStart=/usr/bin/puppet agent --config /etc/puppet/puppet.conf --onetime --no-daemonize --detailed-exitcode --no-usecacheonfailure -SuccessExitStatus=2 -User=root -Group=root - -[Install] -WantedBy=multi-user.target', - } - - file { '/opt/puppetlabs': - ensure => directory, - owner => 'root', - group => 'root', - mode => '0755', - } -} -- GitLab