自動構成:実世界でのCFEngineの練習

CFEngine



以前の 2つの記事で、ユーザーalex_wwwによって開始されたCFEngineの話を続けます。 この記事では、CFEngineの使用法と、実際の環境での構成の微妙な違いに焦点を当てます。 テキストの量を減らすために、CFEngineの世界の基本概念を知っていると思います。おそらくどこかでそれを使おうとしたこともあるでしょう。 入門書として、Diego Zamboniの著書Learning CFEngine 3をお勧めします。



この記事では、 Gitを使用してDebian GNU / Linuxをゼロからセットアップする例を示します 。 お気に入りのディストリビューションとVCSの例で記事を補足する場合は、個人的なメッセージを送信するか、コメントで自分を表現してください。 可能であれば、著者を示すメインテキストに追加します。



設置



CFEngine3をインストールする最も簡単な方法は、公式リポジトリからこれを行うことです。 これを行うには、まずパッケージの署名に使用するキーを追加する必要があります。



cd /tmp wget http://cfengine.com/pub/gpg.key cat gpg.key #      apt-key add gpg.key rm gpg.key #  ,   
      
      







...次に、リポジトリを追加してCFEを配置します。



 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
      
      







初期化



CFEを初期化するには、cf-agentの最初の起動を(たとえば、手動で)実行する必要があります。 新しいサーバーを頻繁にコミッションする必要がある場合、CFEとブートストラップのインストールは、 preseedまたはシステムの最初の起動時に1回実行されるスクリプトから行うのが最適です。 このようなスクリプトの良い例は、OpenSSHのサーバーキーを作成するスクリプトです。



 /var/cfengine/bin/cf-agent -IC --bootstrap <policy_hub_address>
      
      







<policy_hub_address>



代わりに、ポリシーハブの対応するIPアドレスまたはドメイン名を置き換える必要があります。ポリシーハブ自体を初期化する場合、クライアントにサービスを提供するIPを指定する必要があります。 ドメイン名の場合、将来使用されるIPアドレスに解決されるため、DNSサーバーが使用できない可能性があるという問題が障害になることはありません。



-I



は短い実行レポートの作成を有効にし、 -C



はコンソールでの出力の色付けを有効にします。 両方ともオプションですが、私は自分の都合のためにインタラクティブなセッションでそれらを使用します。 別の便利な起動オプションは-v



、冗長モードです。 -I



よりも優先され、 -I



の進捗に関する非常に詳細な情報を提供します。 デバッグに最適です。



初期設定



ポリシーハブの初期化後、最初のクライアントに接続する前であっても、いくつかの小さな設定を行う必要があります。 実際のところ、 def.cf



ファイルのデフォルトのパラメーター(以降、すべての相対パスについて、特に指定のない限り、ルートは/var/cfengine/masterfiles



def.cf



であるとdef.cf



ます)は、「 def.cf



」の実験や機能の実証に適しています。これらのパラメータを販売することは適切ではありません。 以下に、プロミスを開発してプロッドに展開するプロセスの構成について説明しますが、今のところは、 /var/cfengine/masterfiles



ローカルコピーを作成し、それを操作することをお勧めします。



まず、完全修飾ドメイン名を示します。 システムの現在のパラメーターを自動的に決定するための優れたシステムを作成するための開発チームの努力にもかかわらず、不完全であるため、可能な限り自動化に依存せず、手動でデータを指定しないことが最善です。 bundle common def



から始めて、 domain



mailto



mailfrom



および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}';
      
      







安全性



CFEは接続セキュリティとクライアント認証を提供できますが、タスクを完了するのに十分な目があるため、このための特別に開発された手段はありません。 クライアントとの通信では、OpenSSHと同様に、信頼できるキーを持つシステムと、信頼できるIPネットワークとドメインのリストが使用されます。 デフォルトでは、接続はポリシーハブドメイン内のすべてのホストおよびプライマリIPの/ 16に対して許可されます。 正常に確立された接続を通じて受信したすべてのキーは、信頼できると見なされます。 信頼できるネットワーク環境でのこのようなアプローチは、ゼロからの展開を非常に容易にし、研究開発段階では非常に便利ですが、実際には非常に安全ではありません。 IPアドレスのcf-serverd



と制御されるマシンの地理的分布を考えると、次のアプローチを使用することを好みます:CFEngine(より正確にはcf-serverd



)は、任意のIPアドレスからの接続を受け入れ、事前に認識されている(つまり、 /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';
      
      







IPアドレスでアクセスを制限する必要がある場合、問題を解決するためのより適切なツールとしてファイアウォールを使用することを好みます。



クライアントキーを信頼できるキーに追加するには、ファイル/var/cfengine/ppkeys/localhost.pub



の通常のRSAキー)の内容をポリシーハブにコピーし、 cf-key -t /path/to/client_key.pub



を実行する必要があります。 cf-key



プログラムは、正しい名前と権限で/var/cfengine/ppkeys



します。



標準ライブラリ



構成制御の自動化により、大規模な変更が簡単になり、同じように簡単に大規模なエラーが発生します。 したがって、合理的な数の「シートベルト」と「大きな赤いボタン」が必要です。 これらの「ストラップ」の1つは、コードとともに標準ライブラリをVCSに追加することです。 新しいバージョンでパッケージをインストールする場合、 /var/cfengine/masterfiles



および/var/cfengine/inputs



更新されません。これは、構成の一貫性を保証できないためです。 したがって、更新の重要な段階の1つは、標準ライブラリの変更をコピーにマージすることです。ここで、VCSが提供できるすべてのヘルプと、 diff



およびpatch



ユーティリティを使用する機能が役立ちます。



package_latests



一部のパッケージの更新を保証するためによく使用するメカニズムの1つは、標準ライブラリのpackage_latest



バンドルです。 残念ながら、Debianのバンドルが機能しないバグがあります。 修正は非常に簡単です。 lib/3.6/packages.cf



ファイルで、バンドルコードpackages_latest



を見つけて、次のようにする必要があります(バグレポートのパッチを使用できます)。



 debian:: "$(package)" package_policy => "addupdate", package_version => "999999999:9999999999", package_method => apt_get_permissive;
      
      







バグ6870



prodで見つけたもう1つの迷惑なバグはbug 6870です。 問題の本質は、CFEngineがインターフェイス上のIPアドレスのPTRレコードに基づいていくつかのクラスを設定することです。 ご想像のとおり、このようなシステムの動作は非常に安全ではなく、外部の知識を受け入れられないというCFEngineの仮説と矛盾します。 しかし、彼の本の中で、Diego Zamboniは、 host1_example_org



の形式のクラスによって実行ホストを決定することを教えてhost1_example_org



、このバグを修正すると、現在動作している多くのシステムを破壊することができます。 したがって、開発者がより信頼性の高い方法を提供するまで、私たちはそれを自分で作成します。 lib/3.6/bug_6870.cf



の標準ライブラリのバージョンに追加できるコードは次のlib/3.6/bug_6870.cf







 bundle common bug_6870_workaround { classes: 'bug6870_workaround_${sys.host}' expression => 'any'; }
      
      







次に、ファイル名を${stdlib_common.inputs}



に追加して、そこに既にリストされているファイルと類推し、他のIPのPTRレコードとの予期しない交差を恐れずにbug6870_workaround_host1_example_org



クラスを使用するbug6870_workaround_host1_example_org



があります。



ライフサイクル



すべてが創造性を発揮する準備ができたので、約束を作成するプロセスを整理することについて少しお話しします。



ツール



まず、約束は何かで書く必要があります。 これには、ほとんどの場合、お気に入りのテキストエディターが適しています。 私はVimを好み、Niel Watsonが作成したプラグインを使用します。同僚のValera Astraverkhau は、 Sublime Text 2および3でCFEngineをサポートする非常に優れたプラグインを作成しました 。Emacsユーザーは、Ted Zlatanov EmacsをCFEngine IDEとして使用します。



優れたバージョン管理システムも必要です。 Gitは誰もが大丈夫ですが、現代のVCSはきっと動作するでしょう。 ここでの要件は、従来のソフトウェアの開発と同じであるため、使い慣れたものを使用してください。



ファイル構成とエントリポイント



私が提案した方法だけが真の方法ではないことをすぐに言います。 PerlプログラマーになじみのあるTIMTOWTDIの原則がここに適用されます。 ここで論争に関連する場所は他にありません。 プロジェクトルートに関連するディレクトリ構造の例を次に示します。



 /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



ディレクトリには、作成中のコードが含まれています。 /masterfiles



の残りのサブディレクトリは、どうしても必要な場合を除き、変更しないようにしようとする標準/masterfiles



一部です。 すべての非標準テンプレートは/templates



および/static



で作成されます。名前が示すように、「静的」情報は保存されます-公開SSHキー、ファイアウォール設定、ユーザー設定、構成ファイルなど、ホスト間で変更されません。 /bin



は、「大きな赤いボタン」を含むいくつかのサービススクリプトが含まれています。これは、CFEngineがクライアントにファイルを配布できる場所に必要なすべてのファイルを転送するスクリプトです。



エントリポイントは/masterfiles/example_org/main.cf



にあります。これには、使用されるファイルとサーバー分類を一覧表示するbundle common example_org



と、クラスに応じて、方法を説明する必要なバンドルに制御が転送されるbundle agent example_org_main



が含まれますこのクラスのサーバーを構成する必要があります。



promises.cf



ファイルでエントリポイントを指定するには、次の変更を行う必要があります。



 body common control { bundlesequence => { # [...] @{example_org.bundles}, }; inputs => { # [...] 'example_org/main.cf', @{example_org.inputs}, }; }
      
      







example_org/main.cf



は次のようになります。



 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'; }
      
      







この例は、実際にはもちろん、すべてが少し複雑で大きくなっていることを示すために、いくつかの実際のプロジェクトで構成されています。 このアプローチの目的は、標準ライブラリの変更の数を最小限に抑えることです。これにより、後で変更を維持しやすくなります。



デバッグとテスト



エラーの価格は高いため、「大きな赤いボタン」をクリックする前に、約束をテストする必要があります。 テストのために、私には小さなテストの場があります。仕事用コンピューターで実行するいくつかの仮想マシンです。 それらについて、 約束の履行の正しさを確認し、実験を行います。



promiseの開発では、printfを介してデバッグスクールのスタイルを順守します。つまり、レポートタイプのpromiseを非常に広く使用しています。 もう1つの不可欠なツールは、完全なcf-promises



ユーティリティです。 正式な構文検証に加えて、実行時に使用可能なすべてのクラス( --show-classes



パラメーター)およびその内容を含む変数( --show-vars



)を--show-vars



。 そしてもちろん、 cf-agent



を冗長モード( --verbose



パラメーター)で実行します。



更新情報



すべての制御マシンでCFEngineバージョンを更新するには、パッケージマネージャーを使用する方法と、CFEngine自体のメカニズムを使用する方法の2つがあります。 パッケージマネージャーの方が好きです。パッケージマネージャーは、更新の期間中のみ接続するという特別な約束があり、その本質はpackage_latest



呼び出しにpackage_latest



ます。 私の意見では、このアプローチはCFEの概念に最適です。



大きな赤いボタン



製品への展開は、一日に何度も発生する場合でも、常にエキサイティングな瞬間であり、このための何らかの儀式を持っている人々を非難しません。 大規模な構成変更の場合、これにより、何か問題が発生した場合の今後数日間の人生の意味を判断できます。 したがって、自動化もGitのフックもありません。 すべてが正しく行われ、テストされ、販売の準備ができているという信頼の保証として、手動モードのみ。 権利0600



deploy.sh



スクリプトはボタンとして機能するため、偶然開始することはできません。 コンソールでbash bin/deploy.sh



が私の儀式であり、起動をキャンセルする最後の機会です。 スクリプト自体は非常に簡単ですcf-agent -KIC -f update.cf



と、 cf-agent -KIC -f update.cf



/var/cfengine/{masterfiles,static,templates}



/var/cfengine/{masterfiles,static,templates}



cf-agent -KIC -f update.cf



およびcf-agent -KIC -f promises.cf



2つのコマンドを実行しますcf-agent -KIC -f promises.cf



。 したがって、少なくともポリシーハブは約束を果たし、すべてのクライアントにそれを配布できると確信できます。



おわりに



これはすべての微妙さと知恵からは程遠いですが、これは自宅でCFEngineの実装を開始するのに十分です。 記事以外にも、「 デザインセンター 」、レポート、内部設計、さまざまな使用シナリオなど、興味深いトピックがありました。 CFEngineがhabrasocietyに興味を持っているなら、私はそれについて喜んで話しますが、今のところ、あなたが今緊急の質問を持っているなら、コメントでそれらを尋ねることをheしないでください。 私の同僚とlastops cagliostro 、私はそれらに答えようとします。



All Articles