cd /tmp wget http://cfengine.com/pub/gpg.key cat gpg.key # apt-key add gpg.key rm gpg.key # ,
echo "deb http://cfengine.com/pub/apt community main" > /etc/apt/sources.list.d/cfengine-community.list chmod 644 /etc/apt/sources.list.d/cfengine-community.list # umask 0700 apt-get update apt-get install cfengine-community
/var/cfengine/bin/cf-agent -IC --bootstrap <policy_hub_address>
<policy_hub_address>
you need to substitute the appropriate IP address or domain name of your policy hub, and if you initialize the policy hub itself, then you need to specify the IP on which it will serve clients later. In the case of a domain name, it will be resolved to an IP address, which will be used in the future, so that problems with the possible unavailability of DNS servers will not interfere.-I
enables the creation of a short report on the execution, and -C
- coloring the output in the console. Both are optional, but I use them in interactive sessions for my own convenience. Another useful startup option is -v
, verbose mode. It takes precedence over -I
and gives you very detailed information on the progress of the promises. Nice helps when debugging.def.cf
file (hereinafter, for all relative paths, the root is /var/cfengine/masterfiles
, unless otherwise specified) are well suited for “on the knee” experiments or for demonstration of capabilities, but for Sell ​​these options are not enough. Below, I will write about the organization of the process of developing promises and rolling them out in the product, but for now it is best to make a local copy of /var/cfengine/masterfiles
and work with it.bundle common def
, and specify the domain
, mailto
, mailfrom
and smtpserver
: 'domain' string => 'example.org'; 'mailto' string => 'sysadmin-queue@${def.domain}'; # CFE 'mailfrom' string => 'root@cfe-policy-server.${def.domain}'; 'smtpserver' string => 'internal-mail-collector.${def.domain}';
cf-serverd
, to be more precise) accepts connections from any IP address and only trusts those keys that it knows in advance (that is, are located in /var/cfengine/ppkeys
): 'acl' slist => { '0.0.0.0/0', }; comment => 'Connections are allowed from any IP', handle => 'common_def_vars_acl'; 'trustkeysfrom' slist => { # NEVER ADD ANYTHING HERE. DON'T TRUST STRANGERS! }, comment => 'Only keys in /var/cfengine/ppkeys are trusted', handle => 'common_def_vars_truskeysfrom';
/var/cfengine/ppkeys/localhost.pub
file (the usual RSA key in Base64) to the policy hub and run cf-key -t /path/to/client_key.pub
. The cf-key
program will add it to /var/cfengine/ppkeys
with the correct name and permissions./var/cfengine/masterfiles
and /var/cfengine/inputs
not updated, as a result, it will be impossible to guarantee the consistency of the configuration. Therefore, one of the important stages of updating is merging the changes of the standard library with your copy and it is here that all the help your VCS can offer you is useful, as well as the ability to use the diff
and patch
utilities.package_latest
bundle from the standard library. Unfortunately, there is a bug because of which the bundle in Debian does not work. Fix is ​​quite trivial. In the file lib/3.6/packages.cf
you need to find the bundle code packages_latest
and bring it to this form (you can use a patch from the bug report): debian:: "$(package)" package_policy => "addupdate", package_version => "999999999:9999999999", package_method => apt_get_permissive;
host1_example_org
type, and fixing this bug can break too many systems currently working. Therefore, until the developers have provided a more reliable method, we will create it ourselves. Here is the code that you can add to your version of the standard library in the file lib/3.6/bug_6870.cf
: bundle common bug_6870_workaround { classes: 'bug6870_workaround_${sys.host}' expression => 'any'; }
${stdlib_common.inputs}
by analogy with the files already listed there, and after that use the bug6870_workaround_host1_example_org
class without fear of unexpected intersections with the PTR records of other IPs. /bin /masterfiles /masterfiles/cfe_internal /masterfiles/cfe_internal/ha /masterfiles/controls /masterfiles/controls/3.4 /masterfiles/inventory /masterfiles/example_org /masterfiles/lib /masterfiles/lib/3.5 /masterfiles/lib/3.6 /masterfiles/services /masterfiles/services/autorun /masterfiles/sketches /masterfiles/sketches/meta /masterfiles/templates /masterfiles/update /static /static/bird-lg /static/firewall-configs /static/ssh-keys /templates
/masterfiles/example_org
is the code that we write. The rest of the subdirectories in /masterfiles
are parts of the standard delivery that I try not to change unless absolutely necessary. All non-standard templates are in /templates
, and in /static
, as the name implies, “static” information is stored - public SSH-keys, firewall settings, user settings, configuration files, etc., which does not change from host to host. There are a couple of service scripts in the /bin
directory, including the “big red button” - a script that puts all the necessary files to where CFEngine can distribute them to customers./masterfiles/example_org/main.cf
, which contains two promises: bundle common example_org
, which lists the files used and the servers are classified, and the bundle agent example_org_main
, where, depending on the class, control is transferred to the necessary bundle, which describes exactly how Servers of this class must be configured.promises.cf
file, you need to make the following changes: body common control { bundlesequence => { # [...] @{example_org.bundles}, }; inputs => { # [...] 'example_org/main.cf', @{example_org.inputs}, }; }
example_org/main.cf
looks like this: bundle common example_org { vars: 'inputs' slist => { 'example_org/add_default_users.cf', 'example_org/basic_packages.cf', 'example_org/configure_dns.cf', 'example_org/configure_firewall.cf', 'example_org/configure_ftp.cf', 'example_org/configure_ssh.cf', 'example_org/cve_2015_0235.cf', 'example_org/lib.cf', }; 'bundles' slist => { 'example_org', 'example_org_main', }; classes: 'ftp_server' or => {classmatch('BUG6870_ftp.*')}; 'dns_server' expression => classmatch('BUG6870_dns.*'); reports: verbose_mode:: '${this.bundle}: defining inputs="${inputs}"'; '${this.bundle}: defining bundles="${bundles}"'; ftp_server:: 'This host assumes FTP server role'; dns_server:: 'This host assumes DNS server role'; } bundle agent example_org_main { methods: any:: 'example_org_update_motd' usebundle => 'update_motd'; 'example_org_basic_packages' usebundle => 'basic_packages'; 'example_org_add_default_users' usebundle => 'add_default_users'; 'example_org_configure_firewall' usebundle => 'configure_firewall'; 'example_org_configure_ssh' usebundle => 'configure_ssh'; 'example_org_cve_2015_0235' usebundle => 'cve_2015_0235'; any.Min30_35:: 'heartbeat' usebundle => 'heartbeat'; # FTP servers configuration ftp_server:: 'example_org_configure_ftp' usebundle => 'configure_ftp'; # DNS servers configuration dns_server:: 'example_org_configure_dns' usebundle => 'configure_dns'; }
report
promises very widely. Another indispensable tool is the complete cf-promises
utility. In addition to the formal validation of the syntax, it can show all classes available at runtime (the --show-classes
parameter) and variables with their contents (the --show-vars
). And of course, running cf-agent
in verbose mode ( --verbose
option).package_latest
. In my opinion, this approach best suits the concepts of CFE.deploy.sh
script with 0600
permissions as a button, so that it can’t be run at random. Using my hands in the bash bin/deploy.sh
console bash bin/deploy.sh
is my ritual and the last opportunity to cancel the launch. The script itself is quite trivial: using rsync
it synchronizes masterfiles
, static
and templates
with the contents of /var/cfengine/{masterfiles,static,templates}
and runs two commands: cf-agent -KIC -f update.cf
and cf-agent -KIC -f promises.cf
. So I can be sure that at a minimum a policy hub can perform promises and distribute them to all customers.Source: https://habr.com/ru/post/249249/
All Articles