From 14406cc14a4d832fe83df5da27937051e41dd093 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 3 Jan 2013 13:40:24 -0600 Subject: Cfg: Added feature to provide generation of SSH keys, authorized_keys file --- doc/development/cfg.txt | 16 ++- doc/exts/xmlschema.py | 37 ++++-- doc/server/plugins/generators/cfg.txt | 215 +++++++++++++++++++++++++++++++++- 3 files changed, 254 insertions(+), 14 deletions(-) (limited to 'doc') diff --git a/doc/development/cfg.txt b/doc/development/cfg.txt index ba71232e7..6533e0d7a 100644 --- a/doc/development/cfg.txt +++ b/doc/development/cfg.txt @@ -20,10 +20,11 @@ implement more than one handler type. Cfg Handler Types ================= -There are four different types of Cfg handlers. A new handler must +There are several different types of Cfg handlers. A new handler must inherit either from one of these classes, or from an existing handler. .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgGenerator +.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgCreator .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgFilter .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgInfo .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgVerifier @@ -43,6 +44,7 @@ Cfg Exceptions Cfg handlers may produce the following exceptions: .. autoexception:: Bcfg2.Server.Plugins.Cfg.CfgVerificationError +.. autoexception:: Bcfg2.Server.Plugins.Cfg.CfgCreationError In addition, Cfg handlers may produce the following base plugin exceptions: @@ -53,10 +55,11 @@ exceptions: .. autoexception:: Bcfg2.Server.Plugin.exceptions.PluginInitError :noindex: -Accessing Configuration Options -=============================== +Global Variables +================ .. autodata:: Bcfg2.Server.Plugins.Cfg.SETUP +.. autodata:: Bcfg2.Server.Plugins.Cfg.CFG Existing Cfg Handlers ===================== @@ -70,6 +73,13 @@ Generators .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgEncryptedGenerator.CfgEncryptedGenerator .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgEncryptedGenshiGenerator.CfgEncryptedGenshiGenerator .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgEncryptedCheetahGenerator.CfgEncryptedCheetahGenerator +.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgAuthorizedKeysGenerator.CfgAuthorizedKeysGenerator + +Creators +-------- + +.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.CfgPrivateKeyCreator +.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator.CfgPublicKeyCreator Filters ------- diff --git a/doc/exts/xmlschema.py b/doc/exts/xmlschema.py index fc5788107..81affc610 100644 --- a/doc/exts/xmlschema.py +++ b/doc/exts/xmlschema.py @@ -299,15 +299,24 @@ class XMLDocumentor(object): def document_complexType(self): rv = nodes.definition_list() + content = self.entity.find("xs:simpleContent", namespaces=NSMAP) + if content is not None: + base = content.xpath("xs:extension|xs:restriction", + namespaces=NSMAP)[0] + attr_container = base + else: + base = None + attr_container = self.entity + ##### ATTRIBUTES ##### table, tbody = self.get_attr_table() - attrs = self.get_attrs(self.entity) + attrs = self.get_attrs(attr_container) if attrs: tbody.extend(attrs) foreign_attr_groups = nodes.bullet_list() - for agroup in self.entity.xpath("xs:attributeGroup", - namespaces=NSMAP): + for agroup in attr_container.xpath("xs:attributeGroup", + namespaces=NSMAP): # if the attribute group is in another namespace, just # link to it ns, name = self.split_ns(agroup.get('ref')) @@ -349,11 +358,17 @@ class XMLDocumentor(object): append_node(rv, nodes.definition, *groups) ##### TEXT CONTENT ##### - if (self.include['text'] and - self.entity.get("mixed", "false").lower() == "true"): - append_node(rv, nodes.term, text("Text content:")) - append_node(rv, nodes.definition, - build_paragraph(self.get_values_from_simpletype())) + if self.include['text']: + if self.entity.get("mixed", "false").lower() == "true": + append_node(rv, nodes.term, text("Text content:")) + append_node(rv, nodes.definition, + build_paragraph(self.get_values_from_simpletype())) + elif base is not None: + append_node(rv, nodes.term, text("Text content:")) + append_node( + rv, nodes.definition, + build_paragraph(self.get_values_from_simpletype(content))) + return [rv] def document_attributeGroup(self): @@ -544,8 +559,10 @@ class XMLDocumentor(object): if entity is None: entity = self.entity # todo: xs:union, xs:list - restriction = entity.find("xs:restriction", namespaces=NSMAP) - if restriction is None: + try: + restriction = entity.xpath("xs:restriction|xs:extension", + namespaces=NSMAP)[0] + except IndexError: return "Any" doc = self.get_doc(restriction) if len(doc) == 1 and len(doc[0]) == 0: diff --git a/doc/server/plugins/generators/cfg.txt b/doc/server/plugins/generators/cfg.txt index 94394f98f..a33028a13 100644 --- a/doc/server/plugins/generators/cfg.txt +++ b/doc/server/plugins/generators/cfg.txt @@ -29,7 +29,7 @@ in ``Cfg/etc/passwd/passwd``, while the ssh pam module config file, ``/etc/pam.d/sshd``, goes in ``Cfg/etc/pam.d/sshd/sshd``. The reason for the like-name directory is to allow multiple versions of each file to exist, as described below. Note that these files are exact copies of what -will appear on the client machine (except when using genshi or cheetah +will appear on the client machine (except when using Genshi or Cheetah templating -- see below). Group-Specific Files @@ -355,6 +355,219 @@ either order, e.g.:: To encrypt or decrypt a file, use :ref:`bcfg2-crypt`. +.. _server-plugins-generators-cfg-sshkeys: + +SSH Keys +======== + +.. versionadded:: 1.3.0 + +Cfg can also be used to automatically create and distribute SSH key +pairs and the ``authorized_keys`` file. + +Keys can be created one of two ways: + +* Host-specific keys, where each client has its own key pair. This is + the default. +* Group-specific keys. To do this, you must set ``category`` in + either ``bcfg2.conf`` (see "Configuration" below) or in + ``privkey.xml``. Keys created for a given client will be specific + to that client's group in the specified category. + +Group-specific keys are useful if, for instance, you have multiple +distinct environments (development, testing, production, for example) +and want to maintain separate keys for each environment. + +This feature actually creates static keys, much like the +:ref:`server-plugins-generators-sshbase` plugin creates SSH +certificates. It doesn't generate them on the fly for each request; +it generates the key once, then saves it to the filesystem. + +Creating key pairs +------------------ + +To create an SSH key pair, you need to define how the private key will +be created in ``privkey.xml``. For instance, to create +``/home/foo/.ssh/id_rsa``, you would create +``/var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa/privkey.xml``. + +This will create *both* the private key and the public key; the latter +is created by appending ``.pub`` to the private key filename. It is +not possible to change the public key filename. + +You may *optionally* also create a corresponding ``pubkey.xml``, which +will allow the key pair to be created when the public key is +requested. (For the example above, you'd create +``/var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa.pub/pubkey.xml``. This can +speed up the propagation of SSH keys throughout your managed systems, +particularly if you use the ``authorized_keys`` generation feature. + +``privkey.xml`` +~~~~~~~~~~~~~~~ + +``privkey.xml`` contains a top-level ``PrivateKey`` element, and is +structured as follows: + +.. xml:element:: PrivateKey + :linktotype: + +``pubkey.xml`` +~~~~~~~~~~~~~~~ + +``pubkey.xml`` only ever contains a single line: + +.. code-block:: xml + + + +.. xml:element:: PublicKey + +It acts only as a flag to Bcfg2 that a key pair should be generated, if +none exists, using the associated ``privkey.xml`` file. The path to +``privkey.xml`` is determined by removing ``.pub`` from the directory +containing ``pubkey.xml``. I.e., if you create +``/var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa.pub/pubkey.xml``, then Bcfg2 +will use ``/var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa/privkey.xml`` to +create the key pair. + +Use of ``pubkey.xml`` is optional, but is recommended. If you do not +use ``pubkey.xml`` files, you may encounter two problems: + +* On the first Bcfg2 client run on a given client, the private keys + may be present but the public keys may not be. This will be fixed + by running ``bcfg2`` again. +* If you are including an automatically created public key in + ``authorized_keys``, it will not be created until the client the key + is for requests the key pair. + +As an example of this latter scenario, suppose that your +``authorized_keys.xml`` allows access to foo.example.com from +``/root/.ssh/id_rsa.pub`` for bar.example.com. If bar.example.com has +not run the Bcfg2 client, then no key pair will have been generated, +and generating the foo.example.com ``authorized_keys`` file will +create a warning. But if you create +``Cfg/root/.ssh/id_rsa.pub/pubkey.xml``, then building +``authorized_keys`` for foo.example.com will create root's keypair for +bar.example.com. + +.. note:: + + In order to use ``pubkey.xml``, there *must* be a corresponding + ``privkey.xml``. You cannot, for instance, populate a directory + with manually-generated private SSH keys, drop ``pubkey.xml`` in + the related public key directory, and expect Bcfg2 to generate the + public keys. It will not. + +Examples +~~~~~~~~ + +``privkey.xml`` can, at its simplest, be very simple indeed: + +.. code-block:: xml + + + +This will create a private key with all defaults. Or it can be more +complex: + +.. code-block:: xml + + + + + U2FsdGVkX19xACol83uyPELP94s4CmngD12oU6PLLuE= + + + +This creates a 1024-bit DSA key for each group in the ``environment`` +category, and keys for clients in the ``secure`` group will be +protected with the given (encrypted) passphrase. + +To complete the example, assume that this file was saved at +``/var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa/privkey.xml``. If a client +in the ``development`` group, which is a group in the ``environment`` +category, requests the private key, then the following files would be +created:: + + /var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa/id_rsa.G50_development + /var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa.pub/id_rsa.pub.G50_development + +``/var/lib/bcfg2/Cfg/home/foo/.ssh/id_rsa.pub`` would be created if it +did not exist. + +Subsequent clients that were also members of the ``development`` +environment would get the keys that have already been generated. + +``pubkey.xml`` always contains a single empty tag: + +.. code-block:: xml + + + +Generating ``authorized_keys`` +------------------------------ + +``authorized_keys`` can be automatically generated from public SSH +keys that exist in the Cfg tree. The keys in question can be +generated from ``privkey.xml``, or they can be manually created. + +If a key doesn't exist when ``authorized_keys`` is generated, the key +will only be created if ``pubkey.xml`` exists. If that is not the +case, a warning will be produced. + +To generate ``authorized_keys``, create ``authorized_keys.xml``, e.g.: +``/var/lib/bcfg2/Cfg/root/.ssh/authorized_keys/authorized_keys.xml``. + +``authorized_keys.xml`` +~~~~~~~~~~~~~~~~~~~~~~~ + +``authorized_keys.xml`` is structured as follows: + +.. xml:element:: AuthorizedKeys + :linktotype: + +Example +~~~~~~~ + +.. code-block:: xml + + + + + + + + + + + + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDw/rgKQeARRAHK5bQQhAAe1b+gzdtqBXWrZIQ6cIaLgxqj76TwZ3DY4A6aW9RgC4zzd0p4a9MfsScUIB4+UeZsx9GopUj4U6H8Vz7S3pXxrr4E9logVLuSfOLFbI/wMWNRuOANqquLYQ+JYWKeP4kagkVp0aAWp7mH5IOI0rp0A6qE2you4ep9N/nKvHDrtypwhYBWprsgTUXXMHnAWGmyuHGYWxNYBV9AARPdAvZfb8ggtuwibcOULlyK4DdVNbDTAN1/BDBE1ve6WZDcrc386KhqUGj/yoRyPjNZ46uZiOjRr3cdY6yUZoCwzzxvm5vle6mEbLjHgjGEMQMArzM9 vendor@example.com + + + +Configuration +------------- + +In addition to ``privkey.xml`` and ``authorized_keys.xml``, described +above, the behavior of the SSH key generation feature can be +influenced by several options in ``bcfg2.conf``: + ++----------------+---------------------------------------------------------+-----------------------+------------+ +| Option | Description | Values | Default | ++================+=========================================================+=======================+============+ +| ``passphrase`` | Use the named passphrase to encrypt private keys on the | String | None | +| | filesystem. The passphrase must be defined in the | | | +| | ``[encryption]`` section. See :ref:`server-encryption` | | | +| | for more details on encryption in Bcfg2 in general. | | | ++----------------+---------------------------------------------------------+-----------------------+------------+ +| ``category`` | Generate keys specific to groups in the given category. | String | None | +| | It is best to pick a category that all clients have a | | | +| | group from. | | | ++----------------+---------------------------------------------------------+-----------------------+------------+ +| ``decrypt`` | If decrypt is set to ``lax``, then a key that cannot be | ``strict`` or ``lax`` | ``strict`` | +| | decrypted will produce a warning instead of an error. | | | ++----------------+---------------------------------------------------------+-----------------------+------------+ + Deltas ====== -- cgit v1.2.3-1-g7c22