From bf776536ca537dd86f1916b1bb89d0058d4388de Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Fri, 10 Mar 2023 19:06:40 -0300 Subject: [PATCH] add PoC for puppet + fleet MDM (#10424) --- ee/tools/puppet-fleet/examples/profiles.pp | 81 +++++++++++++++++++ .../lib/puppet/functions/add_host_to_team.rb | 13 +++ .../puppet/functions/batch_send_profiles.rb | 12 +++ .../lib/puppet/util/fleet_client.rb | 70 ++++++++++++++++ .../puppet-fleet/manifests/add_profiles.pp | 12 +++ .../puppet-fleet/manifests/add_to_team.pp | 13 +++ ee/tools/puppet-fleet/manifests/profile.pp | 3 + ee/tools/puppet-fleet/metadata.json | 28 +++++++ 8 files changed, 232 insertions(+) create mode 100644 ee/tools/puppet-fleet/examples/profiles.pp create mode 100644 ee/tools/puppet-fleet/lib/puppet/functions/add_host_to_team.rb create mode 100644 ee/tools/puppet-fleet/lib/puppet/functions/batch_send_profiles.rb create mode 100644 ee/tools/puppet-fleet/lib/puppet/util/fleet_client.rb create mode 100644 ee/tools/puppet-fleet/manifests/add_profiles.pp create mode 100644 ee/tools/puppet-fleet/manifests/add_to_team.pp create mode 100644 ee/tools/puppet-fleet/manifests/profile.pp create mode 100644 ee/tools/puppet-fleet/metadata.json diff --git a/ee/tools/puppet-fleet/examples/profiles.pp b/ee/tools/puppet-fleet/examples/profiles.pp new file mode 100644 index 0000000000..022ccf90f7 --- /dev/null +++ b/ee/tools/puppet-fleet/examples/profiles.pp @@ -0,0 +1,81 @@ +$template = @(END) + + + + + PayloadDescription + This profile configuration is designed to apply the CIS Benchmark for + macOS 10.14 (v2.0.0), 10.15 (v2.0.0), 11.0 (v2.0.0), and 12.0 + (v1.0.0) + PayloadDisplayName + CIS - Bluetooth Sharing + PayloadEnabled + + PayloadIdentifier + cis.macOSBenchmark.section2.BluetoothSharing + PayloadScope + System + PayloadType + Configuration + PayloadUUID + 5CEBD712-28EB-432B-84C7-AA28A5A383D8 + PayloadVersion + 1 + PayloadRemovalDisallowed + + PayloadContent + + + PayloadContent + + com.apple.Bluetooth + + Forced + + + mcx_preference_settings + + PrefKeyServicesEnabled + + + + + + + PayloadDescription + Disables Bluetooth Sharing + PayloadDisplayName + Custom + PayloadEnabled + + PayloadIdentifier + 0240DD1C-70DC-4766-9018-04322BFEEAD1 + PayloadType + com.apple.ManagedClient.preferences + PayloadUUID + 0240DD1C-70DC-4766-9018-04322BFEEAD1 + PayloadVersion + 1 + + + + +END + +node default { + fleet::add_to_team{ 'Workstations': } + + fleet::add_profiles {'Workstations': + profiles => [ + inline_template($template) + ] + } + +# fleet::with_team { 'Workstations': +# profiles => [ +# profile::cis_bt_sharing, +# ] +# } +} diff --git a/ee/tools/puppet-fleet/lib/puppet/functions/add_host_to_team.rb b/ee/tools/puppet-fleet/lib/puppet/functions/add_host_to_team.rb new file mode 100644 index 0000000000..d0bf834284 --- /dev/null +++ b/ee/tools/puppet-fleet/lib/puppet/functions/add_host_to_team.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative '../util/fleet_client' + +Puppet::Functions.create_function(:add_host_to_team) do + def add_host_to_team(host_uuid, team_name, fleet_host, fleet_token) + client = Puppet::Util::FleetClient.new(fleet_host, fleet_token) + team_resp = client.team_id_from_name(team_name) + return team_resp if team_resp['error'] + + client.transfer_host(team_resp['output']['teams'][0]['id'], host_uuid) + end +end diff --git a/ee/tools/puppet-fleet/lib/puppet/functions/batch_send_profiles.rb b/ee/tools/puppet-fleet/lib/puppet/functions/batch_send_profiles.rb new file mode 100644 index 0000000000..a91b496fba --- /dev/null +++ b/ee/tools/puppet-fleet/lib/puppet/functions/batch_send_profiles.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'base64' +require_relative '../util/fleet_client' + +Puppet::Functions.create_function(:batch_send_profiles) do + def batch_send_profiles(team_name, profiles, fleet_host, fleet_token) + enc = profiles.map { |p| Base64.encode64(p) } + client = Puppet::Util::FleetClient.new(fleet_host, fleet_token) + client.batch_send_profiles(team_name, enc) + end +end diff --git a/ee/tools/puppet-fleet/lib/puppet/util/fleet_client.rb b/ee/tools/puppet-fleet/lib/puppet/util/fleet_client.rb new file mode 100644 index 0000000000..0382d24b60 --- /dev/null +++ b/ee/tools/puppet-fleet/lib/puppet/util/fleet_client.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'net/http' +require 'net/https' +require 'uri' +require 'json' + +module Puppet + module Util + class FleetClient + def initialize(host, token) + @host = host + @token = token + end + + def transfer_host(_team_id, host_uuid) + uri = URI.parse("#{@host}/api/v1/fleet/hosts/transfer/filter") + req = Net::HTTP::Post.new(uri.request_uri) + # TODO(roperzh): last minute I refactored this into a module and + # the team_id is coming as nil, figure out why and adjust instead + # of hardcoding. + data = { + 'filters' => { query: host_uuid }, + 'team_id' => 1 + } + req.body = data.to_json + send(uri, req) + end + + def team_id_from_name(team_name) + uri = URI.parse("#{@host}/api/v1/fleet/teams?query=#{team_name}") + req = Net::HTTP::Get.new(uri.request_uri) + send(uri, req) + end + + def batch_send_profiles(team_name, profiles) + uri = URI.parse("#{@host}/api/latest/fleet/mdm/apple/profiles/batch?team_name=#{team_name}") + req = Net::HTTP::Post.new(uri.request_uri) + data = { 'profiles' => profiles } + req.body = data.to_json + send(uri, req) + end + + def send(uri, req) + output = {} + output['error'] = false + output['error_message'] = '' + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + req['Authorization'] = "Bearer #{@token}" + + begin + response = http.request(req) + rescue StandardError => e + output['error'] = true + output['error_message'] = e + end + + if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPNoContent) + output['output'] = response.body unless response.body.nil? + else + output['error'] = true + output['error_message'] = response.code + end + + output + end + end + end +end diff --git a/ee/tools/puppet-fleet/manifests/add_profiles.pp b/ee/tools/puppet-fleet/manifests/add_profiles.pp new file mode 100644 index 0000000000..f2438c228e --- /dev/null +++ b/ee/tools/puppet-fleet/manifests/add_profiles.pp @@ -0,0 +1,12 @@ +define fleet::add_profiles ($profiles) { + $fleet_host = lookup('fleet::host', String) + $fleet_token = lookup('fleet::token', String) + + $out = batch_send_profiles($name, $profiles, $fleet_host, $fleet_token) + $error = $out['error'] + if $error { + notify{"Error pushing profiles for team ${name}: ${error_message}": loglevel => 'err'} + } else { + notify{"Team ${name} profiles updated": } + } +} diff --git a/ee/tools/puppet-fleet/manifests/add_to_team.pp b/ee/tools/puppet-fleet/manifests/add_to_team.pp new file mode 100644 index 0000000000..0cfd558ae8 --- /dev/null +++ b/ee/tools/puppet-fleet/manifests/add_to_team.pp @@ -0,0 +1,13 @@ +define fleet::add_to_team () { + $fleet_host = lookup('fleet::host', String) + $fleet_token = lookup('fleet::token', String) + + $udid = $facts['system_profiler']['hardware_uuid'] + $out = add_host_to_team($udid, $name, $fleet_host, $fleet_token) + $error = $out['error'] + if $error { + notify{"Error adding host ${name} to team ${team}: ${error_message}": loglevel => 'err'} + } else { + notify{"Added host ${udid} to team ${name}": } + } +} diff --git a/ee/tools/puppet-fleet/manifests/profile.pp b/ee/tools/puppet-fleet/manifests/profile.pp new file mode 100644 index 0000000000..60626d2222 --- /dev/null +++ b/ee/tools/puppet-fleet/manifests/profile.pp @@ -0,0 +1,3 @@ +define fleet::profile() { + notify{"profile content ${name}": } +} diff --git a/ee/tools/puppet-fleet/metadata.json b/ee/tools/puppet-fleet/metadata.json new file mode 100644 index 0000000000..0490cd49f3 --- /dev/null +++ b/ee/tools/puppet-fleet/metadata.json @@ -0,0 +1,28 @@ +{ + "name": "puppet-fleet", + "author": "", + "license": "", + "version": "0.0.0-beta.0", + "summary": "Puppet Module for managing macOS Configuration Profiles", + "source": "", + "project_page": "", + "issues_url": "", + "tags": [ + "macOS", + "OS X", + "mobileconfig", + "profiles" + ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.4.0" + } + ], + "dependencies": [ + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 2.3.1" + } + ] +}