構成管理システムに新しいドロップレットを自動的に追加する方法
序章
管理者は、DigitalOceanメタデータサービスを使用して、新しいサーバーが自動的に構成できるようにする手順を提供できます。 これは便利ですが、多くの組織は、ChefやPuppetなどの構成管理ツール内ですべてのインフラストラクチャ構成を処理することを好みます。
このガイドでは、メタデータサービスとCloudInitを使用してDigitalOceanサーバーをブートストラップし、既存の構成管理展開に接続する方法を示します。 サーバーの実際の構成は、構成管理サービスで処理できます。 ChefノードとPuppetノードの両方をブートストラップする方法を示します。
前提条件
このガイドを完了するには、DigitalOceanメタデータサービスにある程度精通している必要があります。 メタデータサービスに情報を入力したり、メタデータサービスから情報を取得したりする方法の詳細については、このガイドを参照してください。
このガイドでは、最初の実行構成を実行するために、DropletのCloudInitサービスによって最初の起動時に消費されるcloud-config
と呼ばれるタイプのスクリプトを活用します。 このガイドに示されているスクリプトを変更する方法をよりよく理解するには、cloud-config
スクリプト、それらの構文、および動作について基本的な知識を身に付ける必要があります。 cloud-configスクリプティングの概要はここにあります。 より実用的な例については(フォーマットの制限に関するいくつかの議論とともに)、cloud-configここを使用していくつかの基本的なタスクを実行するためのガイドを読むことができます。
Cloud-Configスクリプトを使用してChefノードをブートストラップする
DigitalOceanメタデータサービスを使用すると、cloud-config
スクリプトを使用して、新しいサーバーを既存のChef制御のインフラストラクチャに簡単に接続できます。
このシステムに新しいサーバーを追加するには、新しいサーバーが構成手順を受け取るために接続できるChefサーバーがすでに構成されている必要があります。 Chefサーバーと管理ワークステーションのデプロイについてサポートが必要な場合は、このガイドに従って開始できます。
一般的な計画
新しいサーバーをオンラインにするときは、Chefサーバーの制御下に置く必要があります。 通常、これは、knife
管理コマンドを使用して新しいサーバーに接続し、bootstrap
サブコマンドを使用することで実現できます。 これにより、新しいサーバーに接続し、Chefクライアントと、新しいノードがChefサーバーに接続できるようにする検証クレデンシャルをインストールします。 その後、Chefクライアントはサーバーに接続し、自身を検証し、新しいクライアントクレデンシャルを受け取り、サーバーから構成をプルダウンし、自身を目的の状態にするために必要なアクションを実行します。
このガイドでは、cloud-config
スクリプトを使用して手動のブートストラップ手順を置き換え、新しいノードがChefサーバーに自動的に接続し、自身を検証し、クライアントクレデンシャルを受け取り、Chefクライアントの初期実行を実行できるようにします。 サーバーは、管理者の手動による支援なしに、最初の起動時にこれを自動的に実行します。
KnifeConfigファイルから必要なデータを収集する
cloud-config
スクリプトを正常にブートストラップするには、knife
コマンドで通常使用できる資格情報にアクセスする必要があります。 具体的には、次の情報が必要です。
- Chef検証名
- 検証キー
- ChefサーバーにアクセスできるURL
この情報はすべて、Chefインフラストラクチャの管理に使用されるワークステーションのknife
構成ファイルで正しい形式で入手できます。 Chefリポジトリ内には、このファイルを含む.chef
という隠しディレクトリが必要です。
Chefリポジトリがワークステーションのホームディレクトリにあり、chef-repo
という名前であるとすると、次のように入力してファイルの内容を出力できます。
cat ~/chef-repo/.chef/knife.rb
必要な情報を以下に示します。
current_dir = File.dirname(__FILE__) log_level :info log_location STDOUT node_name "jellingwood" client_key "#{current_dir}/jellingwood.pem" validation_client_name "digitalocean-validator" validation_key "#{current_dir}/digitalocean-validator.pem" chef_server_url "https://your_server.com/organizations/digitalocean" syntax_check_cache_path "#{ENV['HOME']}/.chef/syntaxcache" cookbook_path ["#{current_dir}/../cookbooks"]
検証名とChefサーバーのURLは、ファイルからそのまま直接取得できます。 これらの値をコピーして、cloud-config
ファイルで使用できるようにします。
validation_key
は、実際のキーが保持されている場所を指します。 上記の例では、これはknife.rb
ファイルと同じディレクトリにあり、digitalocean-validator.pem
と呼ばれていることを示しています。 これは、構成によって異なる可能性があります。
このファイルの内容が必要なので、もう一度cat
コマンドを使用してください。 コマンドを変更して、バリデーターキーに指定された場所を指すようにします。
cat ~/chef-repo/.chef/digitalocean-validator.pem
RSA秘密鍵が表示されます。
-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU . . . sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3 eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO -----END RSA PRIVATE KEY-----
検証キー全体をコピーして、cloud-config
スクリプトですぐに使用できるようにします。
基本的なCloud-ConfigChefクライアントのインストール
上記のデータを取得したら、スクリプトを作成できます。 Chefの設定は、chef
と呼ばれる専用のcloud-config
モジュールを介して実行できます。 cloud-config
には有効なYAMLが含まれている必要があり、スクリプトの最初の行として#cloud-config
が含まれている必要があります。
最初は、スクリプトは次のようになります。
#cloud-config chef:
cloud-config
のドキュメントでは、ChefクライアントをRuby gem、パッケージから、または従来の「オムニバス」インストール方法を使用してインストールできると主張しています。 ただし、実際には、gemメソッドとpackageメソッドの両方が失敗する傾向があるため、「オムニバス」メソッドを使用します。 通常は必要ありませんが、オムニバスインストーラーの場所も明示的にリストします。
force_install
を「false」に設定します。 このように、何らかの理由でChefクライアントがすでにイメージにインストールされている場合(たとえば、スナップショットからデプロイしている場合)、クライアントは再インストールされません。 これまでのところ、スクリプトは次のようになっています。
#cloud-config chef: install_type: "omnibus" omnibus_url: "https://www.opscode.com/chef/install.sh" force_install: false
次に、node_name
ディレクティブを使用して、Chefインフラストラクチャ内の新しいサーバーの名前を選択するオプションがあります。 これを設定しない場合、Chefはサーバーのホスト名を使用するため、これはオプションです。 ただし、これはChef環境で一意である必要があります。
その後、Chefワークステーションから取得したすべての接続情報を追加できます。 server_url
オプションを、knife.rb
ファイルの場合とまったく同じようにChefサーバーの場所に設定します。 validation_name
オプションについても同様です。
検証キーには、YAMLパイプシンボル(|
)を使用して、ワークステーションで見つかった検証キー全体を入力します。
#cloud-config chef: install_type: "omnibus" omnibus_url: "https://www.opscode.com/chef/install.sh" force_install: false node_name: "new_node" server_url: "https://your_server.com/organizations/digitalocean" validation_name: "digitalocean-validator" validation_key: | -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU . . . sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3 eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO -----END RSA PRIVATE KEY-----
この時点で、スクリプトには、Chefサーバーに接続してクライアント資格情報を作成するために必要なすべての認証が含まれています。
Chef Environment、run_list、および属性の構成
上記の詳細は、クライアントがChefサーバーに接続するための十分な情報を提供しますが、実際にそれ自体を構成する方法に関する情報をノードに提供していません。 この情報は、cloud-config
スクリプトでも提供できます。
新しいノードを配置する環境を指定するには、environment
オプションを使用します。 これが設定されていない場合、_default
環境が設定されます。これは、別の環境が与えられていないChefノードの一般的なデフォルトです。
chef: environment: "staging"
run_list
は、クライアントが順番に適用する必要があるアイテムの単純なリストとして指定できます。 これらは、レシピまたはロールのいずれかです。
chef: run_list: - "recipe[lamp]" - "role[backend-web]"
initial_attributes
階層を使用して、新しいノードの初期属性を指定できます。 これにより、run_list
の適用方法に影響を与える初期属性が設定されます。
chef: initial_attributes: lamp: apache: port: 80 mysql: username: webclient pass: $#fjeaiop34S
前のcloud-config
スクリプトに接続すると、次のようになります。
#cloud-config chef: install_type: "omnibus" omnibus_url: "https://www.opscode.com/chef/install.sh" force_install: false node_name: "new_node" server_url: "https://your_server.com/organizations/digitalocean" validation_name: "digitalocean-validator" validation_key: | -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU . . . sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3 eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO -----END RSA PRIVATE KEY----- environment: "staging" run_list: - "recipe[lamp]" - "role[backend-web]" initial_attributes: lamp: apache: port: 80 mysql: username: webclient pass: $#fjeaiop34S
出力のリダイレクトとChefクライアント実行の構成
上記のスクリプトには、chef:
セクションで必要なすべての情報が含まれています。 ただし、他のcloud-config
モジュールを使用して実行する必要がある他のいくつかのことがあります。
まず、すべてのコマンドとサブコマンドからの出力をCloudInitプロセスの出力ログにリダイレクトすることを指定する必要があります。 これはデフォルトで/var/log/cloud-init-output.log
にあります。 これは、output
モジュールを使用して次のように実行できます。
output: {all: '| tee -a /var/log/cloud-init-output.log'}
もう1つ実行したいのは、Chefクライアントをインストールして構成した後、実際に実行するように設定することです。 この記事の執筆時点では、オムニバスのインストール方法はこれを自動的に行いません。
コマンドを呼び出す前に、chef-client
実行可能ファイルがサーバーにインストールされるまで待機することで、この動作を強制できます。 単純なbash
ループを使用して、5秒ごとにこのファイルの存在を確認します。 見つかったら、指定した初期構成を実装するためにchef-client
を実行します。
runcmd
モジュールを使用して、任意のコマンドを発行できます。 bash
ループの理想的な場所です。
runcmd: - while [ ! -e /usr/bin/chef-client ]; do sleep 5; done; chef-client
また、オプションで、別のcloud-config
ディレクティブを追加して、最初の起動後にメタデータエンドポイントをヌルルーティングすることもできます。 これは、ユーザーデータに秘密鍵を入れるので便利です。 メタデータエンドポイントをヌルルーティングしないと、サーバー上のすべてのユーザーがこれにアクセスできます。 次を追加してこれを実装します。
disable_ec2_metadata: true
これらをこれまでに作成したスクリプトと組み合わせると、ノードをブートストラップしてChefインフラストラクチャに接続するために必要な完全なスクリプトを取得できます。
#cloud-config chef: install_type: "omnibus" omnibus_url: "https://www.opscode.com/chef/install.sh" force_install: false node_name: "new_node" server_url: "https://your_server.com/organizations/digitalocean" validation_name: "digitalocean-validator" validation_key: | -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA3O60HT5pwEo6xUwcZ8WtExBUhoL3bTjlsvHVXg1JVmBUES+f V9jLu2N00uSZEDZneCIQyHLBXnqD/UNvWEPNvPzt1ecXzmw2BytB7lPDW4/F/8tJ vAVrKqC7B04VFGmcFY2zC8gf8BWmX8CNRDQooM7UO5OWe/H6GDGPPRIITerO3GrU . . . sWyRAoGBAKNc/ZUM8ljRV0UJxQ9nbdozXRZjtUaNgXMNiw+oP2HYYdHrlkKnGHYJ Js63rvjpq8pocjE8YI+2H0v4/4uWqW8GEBfrWbLMzGsYPnRyiHR5+hgjCUU50RB3 eFoNbURwLYcq2Z/IAQZpDpJWpofz3OVMpMXtei1cIflrAAd2wtWO -----END RSA PRIVATE KEY----- environment: "staging" run_list: - "recipe[lamp]" - "role[backend-web]" initial_attributes: lamp: apache: port: 80 mysql: username: webclient pass: $#fjeaiop34S output: {all: '| tee -a /var/log/cloud-init-output.log'} runcmd: - while [ ! -e /usr/bin/chef-client ]; do sleep 5; done; chef-client disable_ec2_metadata: true
上記のスクリプトは、インフラストラクチャ内の新しいサーバーごとに必要に応じて調整できます。
Cloud-Configスクリプトを使用してPuppetノードをブートストラップする
インフラストラクチャが構成管理をPuppetに依存している場合は、代わりにpuppet
モジュールを使用できます。 Chefの例のように、Puppetノードのブートストラップには、cloud-config
を使用して新しいサーバーを既存の構成管理インフラストラクチャに接続することが含まれます。
開始する前に、インフラストラクチャ用にPuppetマスターサーバーを構成する必要があります。 Puppetサーバーの起動と実行についてサポートが必要な場合は、このガイドを確認してください。
一般的な計画
新しいPuppetサーバーがオンラインになると、Puppetエージェントがインストールされ、Puppetマスターサーバーと通信できるようになります。 このエージェントは、ノードの望ましい状態を指示する情報を受信して適用する責任があります。 これを行うには、エージェントはマスターに接続し、自身に関するデータをアップロードし、目的の状態を説明する現在のカタログをプルダウンして、その状態に到達するために必要なアクションを実行します。
ただし、これが発生する前に、最初の実行時に、エージェントは自分自身をマスターサーバーに登録する必要があります。 証明書署名要求を作成し、それをマスターに送信して署名します。 通常、エージェントは証明書が署名されるまで定期的にマスターに再接続しますが、環境に適している場合は、特定の特性を持つ着信要求に自動的に署名するようにPuppetを構成できます(これについては後で説明します)。
cloud-config
スクリプトを使用して、マスターに初めて接続するために必要な情報を使用して新しいサーバーを構成します。 その時点で、Puppetマスターサーバーからカタログの形式で構成の詳細を取得できます。
パペットマスターから必要なデータを収集する
cloud-config
ファイルを作成する前に最初に行う必要があるのは、接続する必要があるPuppetマスターサーバーからデータを収集することです。 必要な情報はほんのわずかです。
まず、Puppetマスターサーバーの完全修飾ドメイン名(FQDN)を取得する必要があります。 これを行うには、次のように入力します。
hostname -f
ほとんどの場合、次のようなものが返されます。
puppet.example.com
Puppetマスター構成ファイルをチェックして、dns_alt_names
オプションが設定されているかどうかを確認することもできます。
cat /etc/puppet/puppet.conf
. . . dns_alt_names = puppet,puppet.example.com . . .
これらのオプションを設定した後にPuppetマスターのSSL証明書が生成された場合は、それらも使用できる可能性があります。
収集する必要があるもう1つのアイテムは、Puppetマスターの認証局証明書です。 これは、/var/lib/puppet/ssl/certs/ca.pem
または/var/lib/puppet/ssl/ca/ca_crt.pem
のいずれかにあります。
sudo cat /var/lib/puppet/ssl/certs/ca.pem
結果は次のようになります。
-----BEGIN CERTIFICATE----- MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC . . . arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg== -----END CERTIFICATE-----
証明書全体をコピーします。 これをcloud-config
ファイルに含めて、新しいサーバーが正しいPuppetマスターに接続していることを確認できるようにします。
これらの情報を入手したら、cloud-config
ファイルの作成を開始して、新しいサーバーが既存のPuppetインフラストラクチャにプラグインできるようにします。
基本的なCloud-ConfigPuppetノードのインストール
新しいPuppetノードのcloud-config
構成は非常に簡単です。 すべてのPuppet固有の構成は、ファイルのpuppet:
セクション内にあります。 すべてのcloud-config
ファイルと同様に、最初の行には#cloud-config
が含まれている必要があります。
#cloud-config puppet:
この下には、2つのサブセクションしかありません。 1つ目はca_cert
キーです。 これはパイプ文字を使用してYAMLテキストブロックを開始し、CA証明書全体をインデントされたブロックとして指定できるようにします。
#cloud-config puppet: ca_cert: | -----BEGIN CERTIFICATE----- MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC . . . arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg== -----END CERTIFICATE-----
証明書全体を開始マーカーと終了マーカーとともに含め、適切にインデントするようにしてください。
puppet:
傘下の2番目のセクションは、conf:
セクションです。 これは、汎用puppet.conf
ファイルに追加されるキーと値のペアを指定するために使用されます。 キーと値のペアは、puppet.conf
ファイルの場合と同様に、セクションヘッダーの下に配置する必要があります。
たとえば、少なくとも、新しいサーバーはPuppetマスターサーバーのアドレスを知っている必要があります。 puppet.conf
ファイルでは、次のように[agent]
セクションにあります。
. . . [agent] server = puppet.example.com . . .
cloud-config
構文でこれを指定するには、これをこれまでの構文に追加します。
#cloud-config puppet: ca_cert: | -----BEGIN CERTIFICATE----- MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC . . . arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg== -----END CERTIFICATE----- conf: agent: server: "puppet.example.com"
conf:
セクションはca_cert
セクションとインラインであり、子要素ではないことに注意してください。 これは、Puppetマスターに接続するために最低限必要なものです。 puppet.conf
にある追加の構成アイテムは、最初にセクション名のレベルを作成し、次にキーと値のペアを定義することで、同様の方法で追加できます。
この後、今後のすべての出力をcloud-init-output.log
ファイルにリダイレクトし、Chef構成に追加したものと同等のruncmd
行を追加する必要があります。 これにより、Puppetエージェントがインストールされるまで待機してから、有効にして再起動します。 Chefセクションで行ったように、最初の実行後にメタデータエンドポイントをnullルーティングすることもできます。 これらの行cloud-config
ディレクティブは、他のモジュールセクションの外側に配置する必要があります。
. . . conf: agent: server: "puppet.example.com" output: {all: '| tee -a /var/log/cloud-init-output.log'} runcmd: - while [ ! -e /usr/bin/puppet ]; do sleep 5; done; puppet agent --enable; service puppet restart disable_ec2_metadata: true
この情報を使用して、新しいサーバーはPuppetマスターサーバーに接続し、マスターに転送するためのクライアント証明書署名要求を生成できます。 デフォルトでは、クライアント証明書はPuppetマスターで手動で署名する必要があります。 これが完了すると、次のPuppetエージェントの更新間隔(デフォルトでは30分ごと)で、ノードはPuppetマスターから構成をプルダウンします。 この遅延を回避するために、比較的安全な自動署名メカニズムを実装する方法については、少し後で説明します。
ノードの証明書名の定義
新しいサーバーのpuppet.conf
ファイルに配置できる値の1つは、固有のケースです。 cloud-config
ファイルでは、特定の変数が指定されている場合、certname
オプションで環境の値を置き換えることができます。 次の変数が認識されます。
- %i :サーバーのインスタンスID。 これは、サーバーの作成時に
http://169.254.169.254/metadata/v1/id
から取得されます。 これは、液滴を一意に識別するために使用される液滴IDに対応します。 - %f :サーバーのFQDN。
これを念頭に置いて、一般的なcertname
設定は次のようになります。
#cloud-config puppet: . . . conf: agent: server: "puppet.example.com" certname: "%i.%f"
これにより、次のようなパターンのcertname
が生成されます。
|-Droplet ID | | |-Fully Qualified Domain Name | | |-----||-------------------| 123456.testnode.example.com
certname
の一部としてドロップレットIDを使用すると、次のセクションで説明するように、安全なPuppet自動署名を構成するのに役立ちます。
Puppet証明書の自動署名を実装する
管理者の介入の必要性を回避するために証明書自動署名システムを実装したい場合は、いくつかのオプションがあります。 最初にPuppetマスターサーバーでこれを設定する必要があります。
Puppetマスターサーバーのpuppet.conf
ファイルで、ファイルの[master]
セクションの下にあるautosign
オプションを設定できます。 これは、いくつかの異なる値を取ることができます。
- true :これにより、Puppetマスターサーバーは、チェックを行わずに、着信するすべての証明書要求に署名するように指示されます。 これは実際の環境では非常に危険です。どのホストもCSRに署名して、インフラストラクチャに入ることができるからです。
- ':2番目のオプションは、ホストまたはホスト正規表現のホワイトリストとして機能するファイルを指定することです。 Puppetマスターは、このリストに対して証明書署名要求をチェックして、証明書に署名する必要があるかどうかを確認します。 証明書名は簡単にスプーフィングされる可能性があるため、これもお勧めしません。
- ':3番目のオプションは、証明書署名要求に署名する必要があるかどうかを判断するために実行できるスクリプトまたは実行可能ファイルを指定することです。 Puppetは、引数としてcertnameを渡し、標準入力を介してCSR全体を渡します。 終了ステータス0が返された場合、証明書は署名されています。 別のステータスが与えられた場合、証明書は署名されません。
ポリシーベースの自動署名は、自動キー署名を実装するための最も安全な方法です。これにより、正当な要求と非正当な要求を区別する方法を任意に複雑にすることができます。
ポリシーベースの自動署名を示すために、certname
変数を%i
インスタンスID変数を含むcloud-config
に追加できます。 %i.%f
を使用して、選択したホスト名も含まれるようにします。
#cloud-config puppet: conf: agent: server: "puppet.example.com" certname: "%i.%f" ca_cert: | . . .
完全なcloud-config
は次のようになります。
#cloud-config puppet: conf: agent: server: "puppet.example.com" certname: "%i.%f" ca_cert: | -----BEGIN CERTIFICATE----- MIIFXjCCA0agAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFQdXBw ZXQgQ0E6IHB1cHBldDAeFw8xNTAyMTkxOTA0MzVaFw0yMDAyMTkxOTA0MzVaMBwx GjAYBgNVBAMMEVB1cHBldCBDQTogcHVwcGV0MIICIjANBgkqhkiG9w0BAQEFAAOC . . . arsjZT5/CtIhtP33Jl3mCp7U2F6bsk4/GDGRaAsFXjJHvBbL93NzgpkZ7elf0zUP rOcSGrDrUuzuJk8lEAtrZr/IfAgfKKXPqbyYF95V1qN3OMY+aTcrK20XTydKVWSe l5UfYGY3S9UJFrSn9aBsZzN+10HXPkaFKo7HxpztlYyJNI8UVSatcRF4aYYqt9KR UClnR+2WxK5v7ix0CVd4/KpYH/6YivvyTwxrhjF2AksZKg== -----END CERTIFICATE----- output: {all: '| tee -a /var/log/cloud-init-output.log'} runcmd: - while [ ! -e /usr/bin/puppet ]; do sleep 5; done; puppet agent --enable; service puppet restart disable_ec2_metadata: true
Puppetマスターサーバーで、検証スクリプトを設定する必要があります。 RubyはすでにPuppetにインストールされているので、簡単なRubyスクリプトを作成できます。
certname
には%i.%f
形式を使用しているため、certname
の最初の部分(最初のドットの前の部分)が有効なドロップレットIDに対応しているかどうかを確認できます。私たちのアカウントのために。 これは単なるチェックであり、実際にはホワイトリストファイル以上のことはしません。 ただし、必要に応じて、このアイデアをさらに複雑にすることができます。
これを行うには、DigitalOceanコントロールパネルの「Apps&API」セクションからの個人用アクセストークンが必要になります。 また、DigitalOceanRubyライブラリの1つをインストールする必要があります。 以下に、BargeおよびDropletKitDigitalOceanRubyクライアントを使用するいくつかの簡略化されたスクリプトを示します。
Bargeクライアントを使用する場合は、次のように入力して、Puppetマスターにgemをインストールします。
sudo gem install barge
次のスクリプトを使用して、証明書署名要求のcertname
の最初の部分が有効なドロップレットIDに対応しているかどうかを確認できます。
#!/usr/bin/env ruby require 'barge' TOKEN = 'YOUR_DIGITALOCEAN_API_TOKEN' droplet_ids = [] certname = ARGV[0] id_string = certname.slice(0...(certname.index('.'))) id_to_check = id_string.to_i client = Barge::Client.new(access_token: TOKEN) droplets = client.droplet.all droplets.droplets.each do |droplet| droplet_ids << droplet.id end Kernel.exit(droplet_ids.include?(id_to_check))
代わりに、DigitalOceanの公式RubyクライアントであるDropletKitを使用する場合は、次のように入力してgemをインストールできます。
sudo gem install droplet_kit
DropletKitgemはRuby2.0以降でのみ有効であるため、Puppetに付属しているバージョンのRubyを使用している場合はこれが不可能な場合があることに注意してください。
DropletKitのスクリプトは、次のように調整できます。
#!/usr/bin/env ruby require 'droplet_kit' TOKEN = 'YOUR_DIGITALOCEAN_API_TOKEN' droplet_ids = [] certname = ARGV[0] id_string = certname.slice(0...(certname.index('.'))) id_to_check = id_string.to_i client = DropletKit::Client.new(access_token: TOKEN) droplets = client.droplets.all droplets.each do |droplet| droplet_ids << droplet.id end Kernel.exit(droplet_ids.include?(id_to_check))
インストールしたgemに対応するスクリプトを/etc/puppet/validate.rb
というファイルに配置し、次のように入力して実行可能としてマークすることができます。
sudo chmod +x /etc/puppet/validate.rb
次に、puppet.conf
ファイル(Open SourcePuppetを使用している場合は/etc/puppet/puppet.conf
にあります)に以下を追加できます。
. . . [master] autosign = /etc/puppet/validate.rb . . .
Apacheサービスを再起動して、新しい署名ポリシーを実装します。
sudo service apache2 restart
これで、証明書署名要求がPuppetマスターによって受信されると、証明書名の最初の部分がアカウント内の有効なドロップレット名に対応しているかどうかがチェックされます。 これは、実行可能ファイルを使用してリクエストを検証する方法の大まかな例です。
結論
cloud-config
スクリプトを活用することで、新しいサーバーを簡単にブートストラップし、既存の構成管理システムに渡すことができます。 これにより、管理ソリューションの範囲外で重要な変更を行う前に、既存のツールを使用してインフラストラクチャをすぐに制御できます。