From 1759af98b87a81206a88575787b493eeef4c941f Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Sat, 11 Jul 2026 17:24:45 +0200 Subject: [PATCH 1/8] Simplify and improve chef attribute handling Set the attributes in a Ruby file under /etc/chef/client.d/ instead of editing /etc/chef/client.rb Now uses the new whitelist attribute: https://docs.chef.io/client/19/cookbooks/attributes/attribute_persistence/ Local chef config also uses the same file. That means there is no longer a need to use the sanitize script to remove override and default attributes from nodes. --- .chef/config.rb | 24 +------ .../files/default/chef_attributes.rb | 8 +++ .../files/default/chef_normal_attributes.yml | 6 -- site-cookbooks/kosmos-base/recipes/default.rb | 70 ++++++------------- 4 files changed, 32 insertions(+), 76 deletions(-) create mode 100644 site-cookbooks/kosmos-base/files/default/chef_attributes.rb delete mode 100644 site-cookbooks/kosmos-base/files/default/chef_normal_attributes.yml diff --git a/.chef/config.rb b/.chef/config.rb index c081eb4..4663d82 100644 --- a/.chef/config.rb +++ b/.chef/config.rb @@ -8,27 +8,7 @@ data_bag_path "data_bags" encrypted_data_bag_secret "#{current_dir}/encrypted_data_bag_secret" local_mode true # Chef local mode, replacing Solo -# Knife-Zero config, see https://knife-zero.github.io/40_configuration/ -# Prevent attributes from being saved to the node files -knife[:automatic_attribute_whitelist] = %w[ - fqdn - os - os_version - hostname - ipaddress - roles - recipes - ipaddress - platform - platform_version - cloud - cloud_v2 - chef_packages -] - # Added to /etc/chef/client.rb on node bootstrap # https://docs.chef.io/attribute_persistence/ -# Source of truth: site-cookbooks/kosmos-base/files/default/chef_normal_attributes.yml -normal_attrs = YAML.load_file(File.expand_path("../site-cookbooks/kosmos-base/files/default/chef_normal_attributes.yml", __dir__)) -knife[:normal_attribute_allowlist] = normal_attrs -knife[:allowed_normal_attributes] = normal_attrs +# Source of truth: site-cookbooks/kosmos-base/files/default/chef_attributes.rb +client_d_dir(File.expand_path("../site-cookbooks/kosmos-base/files/default/chef_attributes.rb")) diff --git a/site-cookbooks/kosmos-base/files/default/chef_attributes.rb b/site-cookbooks/kosmos-base/files/default/chef_attributes.rb new file mode 100644 index 0000000..07e2706 --- /dev/null +++ b/site-cookbooks/kosmos-base/files/default/chef_attributes.rb @@ -0,0 +1,8 @@ +allowed_automatic_attributes ["fqdn", "os", "os_version", "hostname", + "ipaddress", "roles", "recipes", "ipaddress", + "platform", "platform_version", "cloud", + "cloud_v2", "chef_packages", "zerotier"] +allowed_default_attributes [] +allowed_override_attributes [] +allowed_normal_attributes ["knife_zero", "kosmos_kvm", "kosmos-ejabberd", + "openresty", "vm_host"] diff --git a/site-cookbooks/kosmos-base/files/default/chef_normal_attributes.yml b/site-cookbooks/kosmos-base/files/default/chef_normal_attributes.yml deleted file mode 100644 index 5a6e74e..0000000 --- a/site-cookbooks/kosmos-base/files/default/chef_normal_attributes.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- knife_zero -- kosmos_kvm -- kosmos-ejabberd -- openresty -- vm_host diff --git a/site-cookbooks/kosmos-base/recipes/default.rb b/site-cookbooks/kosmos-base/recipes/default.rb index 5c6fa78..089c527 100644 --- a/site-cookbooks/kosmos-base/recipes/default.rb +++ b/site-cookbooks/kosmos-base/recipes/default.rb @@ -2,57 +2,31 @@ # Cookbook Name:: kosmos-base # Recipe:: default # -# The MIT License (MIT) -# -# Copyright:: 2019, Kosmos Developers -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. + +ruby_block "cleanup client.rb" do + block do + fe = Chef::Util::FileEdit.new("/etc/chef/client.rb") + # Delete old attributes, replaced by allow_*_attributes + fe.search_file_delete_line(/^.*_attribute_whitelist.*/) + fe.write_file + end +end + +cookbook_file "/etc/chef/client.d/attributes.rb" do + source "chef_attributes.rb" + mode "0644" + notifies :create, "ruby_block[reload_client_config]", :immediately +end + +ruby_block "reload_client_config" do + block do + Chef::Config.from_file("/etc/chef/client.rb") + end + action :nothing +end include_recipe "apt" -cookbook_file "/etc/chef/chef_normal_attributes.yml" do - source "chef_normal_attributes.yml" - owner "root" - group "root" - mode "0644" -end - -ruby_block "update allowed_normal_attributes in client.rb" do - block do - whitelist = YAML.load_file("/etc/chef/chef_normal_attributes.yml") - fe = Chef::Util::FileEdit.new("/etc/chef/client.rb") - fe.search_file_replace_line( - /^allowed_normal_attributes.*/, - "allowed_normal_attributes #{whitelist.inspect}" - ) - fe.write_file - - Chef::Config[:allowed_normal_attributes] = whitelist - Chef::Config[:normal_attribute_allowlist] = whitelist - end - not_if do - whitelist = YAML.load_file("/etc/chef/chef_normal_attributes.yml") - client_rb = ::File.read("/etc/chef/client.rb") - whitelist.all? { |attr| client_rb.include?(attr) } - end -end - directory "/etc/apt/keyrings" do mode "0755" action :create From 065eac06b1b509bf834c611754612c756afdd98b Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Sat, 11 Jul 2026 17:29:31 +0200 Subject: [PATCH 2/8] Add a recipe to install the zerotier ohai plugin The attributes are saved as "automatic" attributes and look like this: "zerotier": { "version": "1.16.2", "node_id": "NODEID", "networks": { "NETWORKID": { "network_name": "networkname", "mac": "ff:ff:ff:ff:ff:ff", "status": "OK", "type": "PRIVATE", "interface": "abcdefg", "addresses": [ "10.1.1.255/24" ] } } } Refs #263 --- site-cookbooks/kosmos_zerotier/metadata.rb | 3 ++- .../kosmos_zerotier/recipes/ohai_plugin.rb | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb diff --git a/site-cookbooks/kosmos_zerotier/metadata.rb b/site-cookbooks/kosmos_zerotier/metadata.rb index a67848b..3a193bd 100644 --- a/site-cookbooks/kosmos_zerotier/metadata.rb +++ b/site-cookbooks/kosmos_zerotier/metadata.rb @@ -4,7 +4,8 @@ maintainer_email 'mail@kosmos.org' license 'MIT' description 'Installs/Configures zerotier' long_description 'Installs/Configures zerotier' -version '0.1.0' +version '0.2.0' chef_version '>= 14.0' depends 'kosmos-base' +depends 'zerotier' diff --git a/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb b/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb new file mode 100644 index 0000000..4c89447 --- /dev/null +++ b/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb @@ -0,0 +1,21 @@ +# +# Cookbook:: kosmos_zerotier +# Recipe:: ohai_plugin +# + +include_recipe "zerotier::ohai_plugin" + +ohai "reload_zerotier" do + action :reload + plugin "zerotier" + notifies :run, "ruby_block[save_chef_zero_node]", :delayed +end + +# Force save the node back to disk in Chef Zero +ruby_block "save_chef_zero_node" do + block do + node.save + Chef::Log.info("Node #{node.name} saved to disk with ZeroTier data") + end + action :nothing +end From 010e2d0d64c282e16dad6d748f382fb5658792e7 Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Sat, 11 Jul 2026 17:34:39 +0200 Subject: [PATCH 3/8] Add zerotier ohai plugin to the base role --- roles/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/roles/base.rb b/roles/base.rb index dc838b3..915f41d 100644 --- a/roles/base.rb +++ b/roles/base.rb @@ -3,4 +3,5 @@ name "base" run_list %w( kosmos-base::default kosmos_prometheus::node_exporter + kosmos_zerotier::ohai_plugin ) From 663c4da0a06d6c8ce2ca8b6328d04d4580d9ba87 Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Sat, 11 Jul 2026 17:35:04 +0200 Subject: [PATCH 4/8] Update the prometheus-1 node after running Chef It now contains the attributes from the ohai plugin --- nodes/prometheus-1.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/nodes/prometheus-1.json b/nodes/prometheus-1.json index f834101..aa239ac 100644 --- a/nodes/prometheus-1.json +++ b/nodes/prometheus-1.json @@ -22,6 +22,7 @@ "kosmos-base", "kosmos-base::default", "kosmos_prometheus::node_exporter", + "kosmos_zerotier::ohai_plugin", "kosmos_kvm::guest", "kosmos_prometheus::server", "kosmos_prometheus::alertmanager", @@ -38,6 +39,7 @@ "postfix::_attributes", "postfix::sasl_auth", "hostname::default", + "zerotier::ohai_plugin", "firewall::default" ], "platform": "ubuntu", @@ -53,6 +55,22 @@ "version": "18.2.13", "ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.2.13/lib/ohai" } + }, + "zerotier": { + "version": "1.16.2", + "node_id": "77fcedcdce", + "networks": { + "8541e5153eb4327c": { + "network_name": "virgo", + "mac": "7e:45:48:d3:d8:2b", + "status": "OK", + "type": "PRIVATE", + "interface": "ztsb7vcj2c", + "addresses": [ + "10.1.1.146/24" + ] + } + } } }, "run_list": [ From db69e437d53591e07ebac3318de5f4507a17e8dc Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Sat, 11 Jul 2026 20:08:58 +0200 Subject: [PATCH 5/8] Remove sanitize node script and pre-commit hook This is no longer needed with the properly set allowed attributes --- .githooks/pre-commit | 40 -------------------- README.md | 4 -- scripts/util/sanitize_node.sh | 69 ----------------------------------- 3 files changed, 113 deletions(-) delete mode 100755 .githooks/pre-commit delete mode 100755 scripts/util/sanitize_node.sh diff --git a/.githooks/pre-commit b/.githooks/pre-commit deleted file mode 100755 index e97f9cb..0000000 --- a/.githooks/pre-commit +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT="$(git rev-parse --show-toplevel)/scripts/util/sanitize_node.sh" - -FILES=$(git diff --cached --name-only --diff-filter=ACM -- 'nodes/*.json' || true) - -[[ -z "$FILES" ]] && exit 0 - -DIRTY=0 - -while IFS= read -r file; do - staged_tmp=$(mktemp) - sanitized_tmp=$(mktemp) - - # 1. get staged version - git show ":$file" > "$staged_tmp" - - # 2. sanitize IN PLACE (on temp copy) - cp "$staged_tmp" "$sanitized_tmp" - "$SCRIPT" "$sanitized_tmp" - - # 3. if sanitizer changed file, update working tree - if ! diff -q "$staged_tmp" "$sanitized_tmp" >/dev/null; then - cp "$sanitized_tmp" "$file" - echo "Sanitized: $file" - DIRTY=1 - fi - - rm -f "$staged_tmp" "$sanitized_tmp" - -done <<< "$FILES" - -if [[ "$DIRTY" -ne 0 ]]; then - echo "" - echo "Commit paused, sanitized files must be re-staged." - exit 1 -fi - -exit 0 diff --git a/README.md b/README.md index 1fcb982..e7b2df0 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,6 @@ Clone this repository, `cd` into it, and run: bundle install -### Enable Git hooks - - git config core.hooksPath .githooks - ## Common tasks ### Bootstrap a new host server diff --git a/scripts/util/sanitize_node.sh b/scripts/util/sanitize_node.sh deleted file mode 100755 index 99d4ec3..0000000 --- a/scripts/util/sanitize_node.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -# Strip the top-level "override" and "default" attributes from Chef node JSON files. -# -# Usage: -# ./scripts/util/strip_node_attrs.sh [ ...] -# ./scripts/util/strip_node_attrs.sh --all -# -# A may be a bare node name (e.g. "prometheus-1"), a path relative to the -# repository root (e.g. "nodes/prometheus-1.json"), or an absolute path. -# -# Exit codes: -# 0 - all target files processed successfully -# 1 - one or more targets could not be processed (missing args, missing jq, -# file not found, invalid JSON, or write failure) - -set -uo pipefail - -command -v jq >/dev/null 2>&1 || exit 1 - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || root="$(pwd)" - -targets=() -if [ "$#" -eq 0 ]; then - exit 1 -fi - -for arg in "$@"; do - if [ "$arg" = "--all" ]; then - shopt -s nullglob - for f in "$root"/nodes/*.json; do - targets+=("$f") - done - shopt -u nullglob - continue - fi - - if [[ "$arg" == */* ]]; then - if [[ "$arg" = /* ]]; then - targets+=("$arg") - else - targets+=("$root/$arg") - fi - else - targets+=("$root/nodes/$arg.json") - fi -done - -if [ "${#targets[@]}" -eq 0 ]; then - exit 1 -fi - -rc=0 -for file in "${targets[@]}"; do - [ -f "$file" ] || { rc=1; continue; } - - jq -e . "$file" >/dev/null 2>&1 || { rc=1; continue; } - - tmp="$(mktemp "${file}.XXXXXX")" || { rc=1; continue; } - if jq --indent 2 'del(.override, .default)' "$file" > "$tmp" 2>/dev/null; then - truncate -s -1 "$tmp" 2>/dev/null || true - mv "$tmp" "$file" || { rm -f "$tmp"; rc=1; continue; } - else - rm -f "$tmp" - rc=1 - continue - fi -done - -exit "$rc" From df4f1236de55b67c1376043f94d63de202a4a9df Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Mon, 13 Jul 2026 16:57:24 +0200 Subject: [PATCH 6/8] Clean up white list attributes in client.rb Both old and new styles. We define our allow list in the client.d file --- site-cookbooks/kosmos-base/recipes/default.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site-cookbooks/kosmos-base/recipes/default.rb b/site-cookbooks/kosmos-base/recipes/default.rb index 089c527..9acdbe8 100644 --- a/site-cookbooks/kosmos-base/recipes/default.rb +++ b/site-cookbooks/kosmos-base/recipes/default.rb @@ -6,8 +6,9 @@ ruby_block "cleanup client.rb" do block do fe = Chef::Util::FileEdit.new("/etc/chef/client.rb") - # Delete old attributes, replaced by allow_*_attributes + # Delete whitelist attribute definitions, everything is defined in attributes.rb fe.search_file_delete_line(/^.*_attribute_whitelist.*/) + fe.search_file_delete_line(/^allowed_.*_attributes.*/) fe.write_file end end From 12948be19340cd6175a3556e118a81042d55fb01 Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Mon, 13 Jul 2026 16:58:47 +0200 Subject: [PATCH 7/8] Do not manually save node data It is not needed --- site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb b/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb index 4c89447..36a606a 100644 --- a/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb +++ b/site-cookbooks/kosmos_zerotier/recipes/ohai_plugin.rb @@ -8,14 +8,4 @@ include_recipe "zerotier::ohai_plugin" ohai "reload_zerotier" do action :reload plugin "zerotier" - notifies :run, "ruby_block[save_chef_zero_node]", :delayed -end - -# Force save the node back to disk in Chef Zero -ruby_block "save_chef_zero_node" do - block do - node.save - Chef::Log.info("Node #{node.name} saved to disk with ZeroTier data") - end - action :nothing end From f2e0a0929a960480763931fc47dc20ebf1c134d8 Mon Sep 17 00:00:00 2001 From: Greg Karekinian Date: Mon, 13 Jul 2026 16:59:19 +0200 Subject: [PATCH 8/8] Update garage-16 node file after Chef run --- nodes/garage-16.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/nodes/garage-16.json b/nodes/garage-16.json index 50a0d2b..2377416 100644 --- a/nodes/garage-16.json +++ b/nodes/garage-16.json @@ -22,6 +22,7 @@ "kosmos-base", "kosmos-base::default", "kosmos_prometheus::node_exporter", + "kosmos_zerotier::ohai_plugin", "kosmos_kvm::guest", "kosmos_garage", "kosmos_garage::default", @@ -40,6 +41,7 @@ "postfix::_attributes", "postfix::sasl_auth", "hostname::default", + "zerotier::ohai_plugin", "firewall::default" ], "platform": "ubuntu", @@ -55,6 +57,22 @@ "version": "18.2.13", "ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.2.13/lib/ohai" } + }, + "zerotier": { + "version": "1.16.1", + "node_id": "16133890db", + "networks": { + "8541e5153eb4327c": { + "network_name": "virgo", + "mac": "7e:24:a7:06:85:3e", + "status": "OK", + "type": "PRIVATE", + "interface": "ztsb7vcj2c", + "addresses": [ + "10.1.1.153/24" + ] + } + } } }, "run_list": [