diff --git a/README.md b/README.md index a231563..c951e52 100644 --- a/README.md +++ b/README.md @@ -1,1054 +1,1056 @@ puppetdb ========= #### Table of Contents 1. [Overview - What is the PuppetDB module?](#overview) 2. [Module Description - What does the module do?](#module-description) 3. [Setup - The basics of getting started with PuppetDB module](#setup) 4. [Upgrading - Guide for upgrading from older revisions of this module](#upgrading) 4. [Usage - The classes and parameters available for configuration](#usage) 5. [Implementation - An under-the-hood peek at what the module is doing](#implementation) 6. [Limitations - OS compatibility, etc.](#limitations) 7. [Development - Guide for contributing to the module](#development) 8. [Release Notes - Notes on the most recent updates to the module](#release-notes) Overview -------- By guiding puppetdb setup and configuration with a Puppet master, the PuppetDB module provides fast, streamlined access to data on puppetized infrastructure. Module Description ------------------- The PuppetDB module provides a quick way to get started using PuppetDB, an open source inventory resource service that manages storage and retrieval of platform-generated data. The module will install PostgreSQL and PuppetDB if you don't have them, as well as set up the connection to Puppet master. The module will also provide a dashboard you can use to view the current state of your system. For more information about PuppetDB [please see the official PuppetDB documentation.](http://docs.puppetlabs.com/puppetdb/) Setup ----- **What PuppetDB affects:** * package/service/configuration files for PuppetDB * package/service/configuration files for PostgreSQL (optional, but set as default) * Puppet master's runtime (via plugins) * Puppet master's configuration * **note**: Using the `puppetdb::master::config` class will cause your routes.yaml file to be overwritten entirely (see **Usage** below for options and more information ) * system firewall (optional) * listened-to ports **Introductory Questions** To begin using PuppetDB, you’ll have to make a few decisions: * Which database back-end should I use? * PostgreSQL (default) or our embedded database * Embedded database * **note:** As of PuppetDB 4.0, the embedded database is no longer supported as an option. When running PuppetDB 3.x, we suggest using the embedded database only for experimental environments rather than production, as it does not scale well and can cause difficulty in migrating to PostgreSQL. * Should I run the database on the same node that I run PuppetDB on? * Should I run PuppetDB on the same node that I run my master on? The answers to those questions will be largely dependent on your answers to questions about your Puppet environment: * How many nodes are you managing? * What kind of hardware are you running on? * Is your current load approaching the limits of your hardware? Depending on your answers to all of the questions above, you will likely fall under one of these set-up options: 1. [Single Node (Testing and Development)](#single-node-setup) 2. [Multiple Node (Recommended)](#multiple-node-setup) ### Single Node Setup This approach assumes you will use our default database (PostgreSQL) and run everything (PostgreSQL, PuppetDB, Puppet master) all on the same node. This setup will be great for a testing or experimental environment. In this case, your manifest will look like: node { # Configure puppetdb and its underlying database class { 'puppetdb': } # Configure the Puppet master to use puppetdb class { 'puppetdb::master::config': } } You can provide some parameters for these classes if you’d like more control, but that is literally all that it will take to get you up and running with the default configuration. ### Multiple Node Setup This approach is for those who prefer not to install PuppetDB on the same node as the Puppet master. Your environment will be easier to scale if you are able to dedicate hardware to the individual system components. You may even choose to run the puppetdb server on a different node from the PostgreSQL database that it uses to store its data. So let’s have a look at what a manifest for that scenario might look like: **This is an example of a very basic 3-node setup for PuppetDB.** $puppetdb_host = 'puppetdb.example.lan' $postgres_host = 'postgres.example.lan' node 'master.example.lan' { # Here we configure the Puppet master to use PuppetDB, # telling it the hostname of the PuppetDB node class { 'puppetdb::master::config': puppetdb_server => $puppetdb_host, } } node 'postgres.example.lan' { # Here we install and configure PostgreSQL and the PuppetDB # database instance, and tell PostgreSQL that it should # listen for connections to the `$postgres_host` class { 'puppetdb::database::postgresql': listen_addresses => $postgres_host, } } node 'puppetdb.example.lan' { # Here we install and configure PuppetDB, and tell it where to # find the PostgreSQL database. class { 'puppetdb::server': database_host => $postgres_host, } } This should be all it takes to get a 3-node, distributed installation of PuppetDB up and running. Note that, if you prefer, you could easily move two of these classes to a single node and end up with a 2-node setup instead. ### Enable SSL connections To use SSL connections for the single node setup, use the following manifest: node { # Here we configure puppetdb and PostgreSQL to use ssl connections class { 'puppetdb': postgresql_ssl_on => true, database_host => '', database_listen_address => '0.0.0.0' } # Configure the Puppet master to use puppetdb class { 'puppetdb::master::config': } To use SSL connections for the multiple nodes setup, use the following manifest: $puppetdb_host = 'puppetdb.example.lan' $postgres_host = 'postgres.example.lan' node 'master.example.lan' { # Here we configure the Puppet master to use PuppetDB, # telling it the hostname of the PuppetDB node. class { 'puppetdb::master::config': puppetdb_server => $puppetdb_host, } } node 'postgres.example.lan' { # Here we install and configure PostgreSQL and the PuppetDB # database instance, and tell PostgreSQL that it should # listen for connections to the `$postgres_host`. # We also enable SSL connections. class { 'puppetdb::database::postgresql': listen_addresses => $postgres_host, postgresql_ssl_on => true, puppetdb_server => $puppetdb_host } } node 'puppetdb.example.lan' { # Here we install and configure PuppetDB, and tell it where to # find the PostgreSQL database. We also enable SSL connections. class { 'puppetdb::server': database_host => $postgres_host, postgresql_ssl_on => true } } ### Beginning with PuppetDB Whether you choose a single node development setup or a multi-node setup, a basic setup of PuppetDB will cause: PostgreSQL to install on the node if it’s not already there; PuppetDB postgres database instance and user account to be created; the postgres connection to be validated and, if successful, PuppetDB to be installed and configured; PuppetDB connection to be validated and, if successful, the Puppet master config files to be modified to use PuppetDB; and the Puppet master to be restarted so that it will pick up the config changes. If your logging level is set to INFO or finer, you should start seeing PuppetDB-related log messages appear in both your Puppet master log and your puppetdb log as subsequent agent runs occur. ### Cross-node Dependencies It is worth noting that there are some cross-node dependencies, which means that the first time you add the module's configurations to your manifests, you may see a few failed puppet runs on the affected nodes. PuppetDB handles cross-node dependencies by taking a sort of "eventual consistency" approach. There’s nothing that the module can do to control the order in which your nodes check in, but the module can check to verify that the services it depends on are up and running before it makes configuration changes--so that’s what it does. When your Puppet master node checks in, it will validate the connectivity to the puppetdb server before it applies its changes to the Puppet master config files. If it can’t connect to puppetdb, then the puppet run will fail and the previous config files will be left intact. This prevents your master from getting into a broken state where all incoming puppet runs fail because the master is configured to use a puppetdb server that doesn’t exist yet. The same strategy is used to handle the dependency between the puppetdb server and the postgres server. Hence the failed puppet runs. These failures should be limited to 1 failed run on the puppetdb node, and up to 2 failed runs on the Puppet master node. After that, all of the dependencies should be satisfied and your puppet runs should start to succeed again. You can also manually trigger puppet runs on the nodes in the correct order (Postgres, PuppetDB, Puppet master), which will avoid any failed runs. Upgrading --------- ### Upgrading from 4.x to 5.x Significant parameter changes are listed below: * The PuppetDB module defaults to Puppet 4 pathing and assumes `puppetserver` is the master service by default * The PuppetDB module manages Postgres repos by default. To turn this behavior off, set `manage_package_repo` to `false`. * To specify a specific version of PuppetDB to manage, you'll need to use the `puppetdb::globals` class to set the version of PuppetDB you're using explicitly. The ability to configure the version in the `puppetdb::server` and `puppetdb` class have been removed. For example if your config looked like this before: class {'puppetdb': puppetdb_version => '3.2.4-1.el7', } class { 'puppetdb::master::config': } and you'd still like to use the module with PuppetDB 3.2.4, all you'd have to change would be: class { 'puppetdb::globals': version => '3.2.4-1.el7', } class { 'puppetdb' : } class { 'puppetdb::master::config' : } The `globals` class above takes into account the following PuppetDB 3 and Puppet 4 related changes: * The `puppetdb::master:puppetdb_conf` class has added a `$legacy_terminus` to support the PuppetDB 2.x terminus configuration. * The default `test_url` for the `PuppetDBConnValidator` has also been changed to `/pdb/meta/v1/version` but will default to `/v3/version` when using a PuppetDB 2.x version. * The configuration pathing for Puppet and PuppetDB has changed with Puppet 4 and PuppetDB 3, using PuppetDB 2.x or older assumes the old configuration pathing. See the CHANGELOG file for more detailed information on changes for each release. ### Upgrading from 3.x to 4.x For this release, all dependency versions have been bumped to their latest. Significant parameter changes are listed below: * The PuppetDB module now only supports Puppet 3.7.1 or later * `puppetlabs/postgresql` 4.0.0 or later is now required * `puppetlabs/inifile` 1.1.3 or later is now required * `puppetlabs/firewall` 1.1.3 or later is now required * `puppetlabs/stdlib` 4.2.2 or later is now required * The parameter `manage_firewall` for the class `puppetdb::database::postgresql` has now been removed, since the PostgreSQL module no longer supports this. * The parameter `open_postgres_port` for the class `puppetdb` has also been removed, due to PostgreSQL changes. See the CHANGELOG file for more detailed information on changes for each release. ### Upgrading from 2.x to 3.x For this release a major dependency has changed. The module `pupppetlabs/postgresql` must now be version 3.x. Upgrading the module should upgrade the `puppetlabs/postgresql` module for you, but if another module has a fixed dependency that module will have to be fixed before you can continue. Some other changes include: * The parameter `manage_redhat_firewall` for the class `puppetdb` has now been removed completely in favor of `open_postgres_port` and `open_ssl_listen_port`. * The parameter `manage_redhat_firewall` for the class `puppetdb::database::postgresql`, has now been renamed to `manage_firewall`. * The parameter `manage_redhat_firewall` for the class `puppetdb::server` has now been removed completely in favor of `open_listen_port` and `open_ssl_listen_port`. * The internal class: `puppetdb::database::postgresql_db` has been removed. If you were using this, it is now defunct. * The class `puppetdb::server::firewall` has been marked as private, do not use it directly. * The class `puppetdb::server::jetty_ini` and `puppetdb::server::database_ini` have been marked as private, do not use it directly. ### Upgrading from 1.x to 2.x A major dependency has been changed, so now when you upgrade to 2.0 the dependency `cprice404/inifile` has been replaced with `puppetlabs/inifile`. This may interfere with other modules as they may depend on the old `cprice404/inifile` instead, so upgrading should be done with caution. Check that your other modules use the newer `puppetlabs/inifile` module as interoperation with the old `cprice404/inifile` module will no longer be supported by this module. Depending on how you install your modules, changing the dependency may require manual intervention. Double check your modules contain the newer `puppetlabs/inifile` after installing this latest module. Otherwise, all existing parameters from 1.x should still work correctly. Usage ------ PuppetDB supports a large number of configuration options for both configuring the puppetdb service and connecting that service to the Puppet master. ### puppetdb::globals The `puppetdb::globals` class is intended to provide similar functionality to the `postgresql::globals` class in the `puppetlabs-postgresql` module by exposing a top-level entry-point into the module so that we can properly set defaults for the `puppetdb::params` class based on the version of `puppetdb` you are using. This setting defaults to `present`. You must declare the class to use it: class { 'puppetdb::globals': } **Parameters within `puppetdb::globals`:** #### `version` The version of the `puppetdb` package that should be installed. You may specify an explicit version number, 'present', or 'latest' (defaults to 'present'). ### puppetdb The `puppetdb` class is intended as a high-level abstraction (sort of an 'all-in-one' class) to help simplify the process of getting your puppetdb server up and running. It wraps the slightly-lower-level classes `puppetdb::server` and `puppetdb::database::*`, and it'll get you up and running with everything you need (including database setup and management) on the server side. For maximum configurability, you may choose not to use this class. You may prefer to use the `puppetdb::server` class directly, or manage your puppetdb setup on your own. You must declare the class to use it: class { 'puppetdb': } **Parameters within `puppetdb`:** #### `listen_address` The address that the web server should bind to for HTTP requests. Defaults to `localhost`. Set to `0.0.0.0` to listen on all addresses. #### `listen_port` The port on which the puppetdb web server should accept HTTP requests. Defaults to `8080`. #### `disable_cleartext` If true, the puppetdb web server will only serve HTTPS and not HTTP requests (defaults to false). #### `open_listen_port` If `true`, open the `http_listen_port` on the firewall. Defaults to `false`. #### `ssl_listen_address` The address that the web server should bind to for HTTPS requests. Defaults to `0.0.0.0` to listen on all addresses. #### `ssl_listen_port` The port on which the puppetdb web server should accept HTTPS requests. Defaults to `8081`. #### `disable_ssl` If `true`, the puppetdb web server will only serve HTTP and not HTTPS requests. Defaults to `false`. #### `open_ssl_listen_port` If true, open the `ssl_listen_port` on the firewall. Defaults to `undef`. #### `ssl_protocols` Specify the supported SSL protocols for PuppetDB (e.g. TLSv1, TLSv1.1, TLSv1.2.) ### `postgresql_ssl_on` If `true`, it configures SSL connections between PuppetDB and the PostgreSQL database. Defaults to `false`. #### `cipher_suites` Configure jetty's supported `cipher-suites` (e.g. `SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384`). Defaults to `undef`. #### `migrate` If `true`, puppetdb will automatically migrate to the latest database format at startup. If `false`, if the database format supplied by this version of PuppetDB doesn't match the version expected (whether newer or older), PuppetDB will exit with an error status. Defaults to `true`. ### `manage_dbserver` If true, the PostgreSQL server will be managed by this module. Defaults to `true`. ### `manage_database` If true, the PostgreSQL database will be managed by this module. Defaults to `true`. #### `database` Which database backend to use; legal values are `postgres` (default) or `embedded`. The `embedded` option is not supported on PuppetDB 4.0.0 or later. `embedded` can be used for very small installations or for testing, but is not recommended for use in production environments. For more info, see the [puppetdb docs](http://docs.puppetlabs.com/puppetdb/). #### `database_host` Hostname to use for the database connection. For single case installations this should be left as the default. Defaults to `localhost`, ignored for `embedded` database. #### `database_port` The port that the database server listens on. Defaults to `5432`, ignored for `embedded` database. #### `database_username` The name of the database user to connect as. Defaults to `puppetdb`, ignored for `embedded` database. #### `database_password` The password for the database user. Defaults to `puppetdb`, ignored for `embedded` database. #### `manage_db_password` Whether or not the database password in database.ini will be managed by this module. Set this to `false` if you want to set the password some other way. Defaults to `true` #### `database_name` The name of the database instance to connect to. Defaults to `puppetdb`, ignored for `embedded` database. #### `jdbc_ssl_properties` The text to append to the JDBC connection URI. This should begin with a '?' character. For example, to use SSL for the PostgreSQL connection, set this parameter's value to `?ssl=true`. This setting is only available when using PostgreSQL; when using HyperSQL (the `embedded` database), it does nothing. #### `database_validate` If true, the module will attempt to connect to the database using the specified settings and fail if it is not able to do so. Defaults to `true`. #### `database_embedded_path` *Embedded Database Only* Changes the path location for the HSQLDB database. Does not provide migration for old data, so if you change this value and you have an existing database you will need to manually move the content also. (defaults to package default for 2.x release). #### `node_ttl` The length of time a node can go without receiving any new data before it's automatically deactivated. (defaults to '7d', which is a 7-day period. Set to '0d' to disable auto-deactivation). This option is supported in PuppetDB >= 1.1.0. #### `node_purge_ttl` The length of time a node can be deactivated before it's deleted from the database. (defaults to '14d', which is a 14-day period. Set to '0d' to disable purging). This option is supported in PuppetDB >= 1.2.0. #### `report_ttl` The length of time reports should be stored before being deleted. (defaults to `14d`, which is a 14-day period). This option is supported in PuppetDB >= 1.1.0. #### `gc_interval` This controls how often (in minutes) to compact the database. The compaction process reclaims space and deletes unnecessary rows. If not supplied, the default is every 60 minutes. This option is supported in PuppetDB >= 0.9. #### `log_slow_statements` This sets the number of seconds before an SQL query is considered "slow." Slow SQL queries are logged as warnings, to assist in debugging and tuning. Note PuppetDB does not interrupt slow queries; it simply reports them after they complete. The default value is `10` seconds. A value of 0 will disable logging of slow queries. This option is supported in PuppetDB >= 1.1. #### `conn_max_age` The maximum time (in minutes) for a pooled connection to remain unused before it is closed off. If not supplied, we default to `60` minutes. This option is supported in PuppetDB >= 1.1. #### `conn_keep_alive` This sets the time (in minutes) for a connection to remain idle before sending a test query to the DB. This is useful to prevent a DB from timing out connections on its end. If not supplied, we default to 45 minutes. This option is supported in PuppetDB >= 1.1. #### `conn_lifetime` The maximum time (in minutes) a pooled connection should remain open. Any connections older than this setting will be closed off. Connections currently in use will not be affected until they are returned to the pool. If not supplied, we won't terminate connections based on their age alone. This option is supported in PuppetDB >= 1.4. #### `puppetdb_package` The PuppetDB package name in the package manager. Defaults to `present`. #### `puppetdb_service` The name of the PuppetDB service. Defaults to `puppetdb`. #### `puppetdb_service_status` Sets whether the service should be `running ` or `stopped`. When set to `stopped` the service doesn't start on boot either. Valid values are `true`, `running`, `false`, and `stopped`. #### `confdir` The PuppetDB configuration directory. Defaults to `/etc/puppetdb/conf.d`. #### `vardir` The parent directory for the MQ's data directory. #### `java_args` Java VM options used for overriding default Java VM options specified in PuppetDB package. Defaults to `{}`. See [PuppetDB Configuration](https://puppet.com/docs/puppetdb/latest/configure.html) to get more details about the current defaults. For example, to set `-Xmx512m -Xms256m` options use: { '-Xmx' => '512m', '-Xms' => '256m', } #### `merge_default_java_args` Sets whether the provided java args should be merged with the defaults, or should override the defaults. This setting is necessary if any of the defaults are to be removed. Defaults to true. If `false`, the `java_args` in the PuppetDB init config file will reflect only what is passed via the `java_args` param. #### `max_threads` Jetty option to explicitly set `max-threads`. Defaults to `undef`, so the PuppetDB-Jetty default is used. #### `read_database` Which database backend to use for the read database. Only supports `postgres` (default). This option is supported in PuppetDB >= 1.6. #### `read_database_host` -*This parameter must be set to enable the PuppetDB read-database.* +*This parameter must be set to use another PuppetDB instance for queries.* -The hostname or IP address of the read database server. Defaults to `undef`. -The default is to use the regular database for reads and writes. This option is -supported in PuppetDB >= 1.6. +The hostname or IP address of the read database server. If set to `undef`, and +`manage_database` is set to `true`, it will use the value of the `database_host` +parameter. This option is supported in PuppetDB >= 1.6. #### `read_database_port` -The port that the read database server listens on. Defaults to `5432`. This -option is supported in PuppetDB >= 1.6. +The port that the read database server listens on. If `read_database_host` +is set to `undef`, and `manage_database` is set to `true`, it will use the value of +the `database_port` parameter. This option is supported in PuppetDB >= 1.6. #### `read_database_username` -The name of the read database user to connect as. Defaults to `puppetdb`. This +The name of the read database user to connect as. Defaults to `puppetdb-read`. This option is supported in PuppetDB >= 1.6. #### `read_database_password` -The password for the read database user. Defaults to `puppetdb`. This option is +The password for the read database user. Defaults to `puppetdb-read`. This option is supported in PuppetDB >= 1.6. #### `manage_read_db_password` Whether or not the database password in read-database.ini will be managed by this module. Set this to `false` if you want to set the password some other way. Defaults to `true` #### `read_database_name` -The name of the read database instance to connect to. Defaults to `puppetdb`. -This option is supported in PuppetDB >= 1.6. +The name of the read database instance to connect to. If `read_database_host` +is set to `undef`, and `manage_database` is set to `true`, it will use the value of +the `database_name` parameter. This option is supported in PuppetDB >= 1.6. #### `read_log_slow_statements` This sets the number of seconds before an SQL query to the read database is considered "slow." Slow SQL queries are logged as warnings, to assist in debugging and tuning. Note PuppetDB does not interrupt slow queries; it simply reports them after they complete. The default value is 10 seconds. A value of 0 will disable logging of slow queries. This option is supported in PuppetDB >= 1.6. #### `read_conn_max_age` The maximum time (in minutes) for a pooled read database connection to remain unused before it is closed off. If not supplied, we default to 60 minutes. This option is supported in PuppetDB >= 1.6. #### `read_conn_keep_alive` This sets the time (in minutes) for a read database connection to remain idle before sending a test query to the DB. This is useful to prevent a DB from timing out connections on its end. If not supplied, we default to 45 minutes. This option is supported in PuppetDB >= 1.6. #### `read_conn_lifetime` The maximum time (in minutes) a pooled read database connection should remain open. Any connections older than this setting will be closed off. Connections currently in use will not be affected until they are returned to the pool. If not supplied, we won't terminate connections based on their age alone. This option is supported in PuppetDB >= 1.6. #### `ssl_dir` Base directory for PuppetDB SSL configuration. Defaults to `/etc/puppetdb/ssl` or `/etc/puppetlabs/puppetdb/ssl` for FOSS and PE respectively. #### `ssl_set_cert_paths` A switch to enable or disable the management of SSL certificates in your `jetty.ini` configuration file. #### `ssl_cert_path` Path to your SSL certificate for populating `jetty.ini`. #### `ssl_key_path` Path to your SSL key for populating `jetty.ini`. #### `ssl_ca_cert_path` Path to your SSL CA for populating `jetty.ini`. #### `ssl_deploy_certs` A boolean switch to enable or disable the management of SSL keys in your `ssl_dir`. Default is `false`. #### `ssl_key` Contents of your SSL key, as a string. #### `ssl_cert` Contents of your SSL certificate, as a string. #### `ssl_ca_cert` Contents of your SSL CA certificate, as a string. #### `manage_firewall` If `true`, puppet will manage your iptables rules for PuppetDB via the [puppetlabs-firewall](https://forge.puppetlabs.com/puppetlabs/firewall) class. #### `command_threads` The number of command processing threads to use. Defaults to `undef`, using the PuppetDB built-in default. #### `concurrent_writes` The number of threads allowed to write to disk at any one time. Defaults to `undef`, which uses the PuppetDB built-in default. #### `store_usage` The amount of disk space (in MB) to allow for persistent message storage. Defaults to `undef`, using the PuppetDB built-in default. #### `temp_usage` The amount of disk space (in MB) to allow for temporary message storage. Defaults to `undef`, using the PuppetDB built-in default. #### `disable_update_checking` Setting this to true disables checking for updated versions of PuppetDB and sending basic analytics data to Puppet. Defaults to `undef`, using the PuppetDB built-in default. #### `certificate_whitelist_file` The name of the certificate whitelist file to set up and configure in PuppetDB. Defaults to `/etc/puppetdb/certificate-whitelist` or `/etc/puppetlabs/puppetdb/certificate-whitelist` for FOSS and PE respectively. #### `certificate_whitelist` Array of the X.509 certificate Common Names of clients allowed to connect to PuppetDB. Defaults to empty. Be aware that this permits full access to all Puppet clients to download anything contained in PuppetDB, including the full catalogs of all nodes, which possibly contain sensitive information. Set to `[ $::servername ]` to allow access only from your (single) Puppet master, which is enough for normal operation. Set to a list of Puppet masters if you have multiple. #### `automatic_dlo_cleanup` PuppetDB creates [Dead Letter Office](https://puppet.com/docs/puppetdb/5.2/maintain_and_tune.html#clean-up-the-dead-letter-office). Those are reports of failed requests. They spill up the disk. This parameter is a boolean and defaults to false. You can enable automatic cleanup of DLO reports by setting this to true. #### `cleanup_timer_interval` The DLO cleanup is a systemd timer if systemd is available, otherwise a cronjob. The variable configures the systemd.timer option [onCalender](https://www.freedesktop.org/software/systemd/man/systemd.timer.html#OnCalendar=). It defaults to `*-*-* ${fqdn_rand(24)}:${fqdn_rand(60)}:00`. This will start the cleanup service on a daily basis. The exact minute and hour is random per node based on the [fqdn_rand](https://puppet.com/docs/puppet/5.5/function.html#fqdnrand) method. On non-systemd systems, the cron runs daily and the `$puppetdb_user` needs to be able to run cron jobs. On systemd systems you need the [camptocamp/systemd](https://forge.puppet.com/camptocamp/systemd) module, which is an optional dependency and not automatically installed! #### `dlo_max_age` This is a positive integer. It describes the amount of days you want to keep the DLO reports. The default value is 90 days. ### puppetdb::server The `puppetdb::server` class manages the PuppetDB server independently of the underlying database that it depends on. It will manage the PuppetDB package, service, config files, etc., but will still allow you to manage the database (e.g. PostgreSQL) however you see fit. class { 'puppetdb::server': database_host => 'pg1.mydomain.com', } ### puppetdb::master::config The `puppetdb::master::config` class directs your Puppet master to use PuppetDB, which means that this class should be used on your Puppet master node. It’ll verify that it can successfully communicate with your PuppetDB server, and then configure your master to use PuppetDB. Using this class allows the module to manipulate the puppet configuration files puppet.conf and routes.yaml. The puppet.conf changes are supplemental and should not affect any of your existing settings, but the routes.yaml file will be overwritten entirely. If you have an existing routes.yaml file, you will want to take care to use the `manage_routes` parameter of this class to prevent the module from managing that file, and you’ll need to manage it yourself. class { 'puppetdb::master::config': puppetdb_server => 'my.host.name', puppetdb_port => 8081, } **Parameters within `puppetdb::master::config`:** #### `puppetdb_server` The dns name or ip of the PuppetDB server. Defaults to the hostname of the current node, i.e. `$::fqdn`. #### `puppetdb_port` The port that the PuppetDB server is running on. Defaults to `8081`. #### `puppetdb_disable_ssl` If true, use plain HTTP to talk to PuppetDB. Defaults to the value of `disable_ssl` if PuppetDB is on the same server as the Puppet Master, or else false. If you set this, you probably need to set `puppetdb_port` to match the HTTP port of the PuppetDB. #### `puppetdb_soft_write_failure` Boolean to fail in a soft manner if PuppetDB is not accessible for command submission Defaults to `false`. #### `manage_routes` If `true`, the module will overwrite the Puppet master's routes file to configure it to use PuppetDB. Defaults to `true`. #### `manage_storeconfigs` If `true`, the module will manage the Puppet master's storeconfig settings. Defaults to `true`. #### `manage_report_processor` If `true`, the module will manage the 'reports' field in the puppet.conf file to enable or disable the PuppetDB report processor. Defaults to `false`. #### `manage_config` If `true`, the module will store values from `puppetdb_server` and `puppetdb_port` parameters in the PuppetDB configuration file. If `false`, an existing PuppetDB configuration file will be used to retrieve server and port values. #### `create_puppet_service_resource` If `true`, AND if `restart_puppet` is true, then the module will create a service resource for `puppet_service_name` if it has not been defined. Defaults to `true`. If you are already declaring the `puppet_service_name` service resource in another part of your code, setting this to `false` will avoid creation of that service resource by this module, avoiding potential duplicate resource errors. #### `strict_validation` If `true`, the module will fail if PuppetDB is not reachable, otherwise it will preconfigure PuppetDB without checking. #### `enable_reports` Ignored unless `manage_report_processor` is `true`, in which case this setting will determine whether or not the PuppetDB report processor is enabled (`true`) or disabled (`false`) in the puppet.conf file. #### `enable_storeconfigs` Ignored unless `manage_storeconfigs` is `true`, in which case this setting will determine whether or not client configuration storage is enabled (`true`) or disabled (`false`) in the puppet.conf file. #### `puppet_confdir` Puppet's config directory. Defaults to `/etc/puppet`. #### `puppet_conf` Puppet's config file. Defaults to `/etc/puppet/puppet.conf`. #### `masterless` A boolean switch to enable or disable the masterless setup of PuppetDB. Defaults to `false`. #### `terminus_package` Name of the package to use that represents the PuppetDB terminus code. Defaults to `puppetdb-termini`, when `puppetdb_version` is set to `<= 2.3.x` the default changes to `puppetdb-terminus`. #### `puppet_service_name` Name of the service that represents Puppet. You can change this to `apache2` or `httpd` depending on your operating system, if you plan on having Puppet run using Apache/Passenger for example. #### `puppetdb_startup_timeout` The maximum amount of time that the module should wait for PuppetDB to start up. This is most important during the initial install of PuppetDB (defaults to 15 seconds). #### `restart_puppet` If `true`, the module will restart the Puppet master when PuppetDB configuration files are changed by the module. Defaults to `true`. If set to `false`, you must restart the service manually in order to pick up changes to the config files (other than `puppet.conf`). ### puppetdb::database::postgresql The `puppetdb::database::postgresql` class manages a PostgreSQL server for use by PuppetDB. It can manage the PostgreSQL packages and service, as well as creating and managing the PuppetDB database and database user accounts. class { 'puppetdb::database::postgresql': listen_addresses => 'my.postgres.host.name', } #### `listen_addresses` The `listen_address` is a comma-separated list of hostnames or IP addresses on which the postgres server should listen for incoming connections. This defaults to `localhost`. This parameter maps directly to PostgreSQL's `listen_addresses` config option. Use a `*` to allow connections on any accessible address. #### `database_name` Sets the name of the database. Defaults to `puppetdb`. #### `database_username` Creates a user for access the database. Defaults to `puppetdb`. #### `database_password` Sets the password for the database user above. Defaults to `puppetdb`. #### `manage_server` Conditionally manages the PostgreSQL server via `postgresql::server`. Defaults to `true`. If set to `false`, this class will create the database and user via `postgresql::server::db` but not attempt to install or manage the server itself. #### `test_url` The URL to use for testing if the PuppetDB instance is running. Defaults to `/pdb/meta/v1/version`. #### `manage_package_repo` If `true`, the official postgresql.org repo will be added and postgres won't be installed from the regular repository. Defaults to `true`. #### `postgres_version` If the postgresql.org repo is installed, you can install several versions of postgres. Defaults to `9.6` in module version 6.0+ and `9.4` in older versions. Implementation --------------- ### Resource overview In addition to the classes and variables mentioned above, PuppetDB includes: **puppetdb::master::routes** Configures the Puppet master to use PuppetDB as the facts terminus. *WARNING*: the current implementation simply overwrites your routes.yaml file; if you have an existing routes.yaml file that you are using for other purposes, you should *not* use this. class { 'puppetdb::master::routes': puppet_confdir => '/etc/puppet' } The optional parameter routes can be used to specify a custom route configuration. For example to configure routes for masterless puppet. class { 'puppetdb::master::routes': routes => { 'apply' => { 'facts' => { 'terminus' => 'facter', 'cache' => 'puppetdb_apply', } } } } **puppetdb::master::storeconfigs** Configures the Puppet master to enable storeconfigs and to use PuppetDB as the storeconfigs backend. class { 'puppetdb::master::storeconfigs': puppet_conf => '/etc/puppet/puppet.conf' } **puppetdb::server::validate_db** Validates that a successful database connection can be established between the node on which this resource is run and the specified PuppetDB database instance (host/port/user/password/database name). puppetdb::server::validate_db { 'validate my puppetdb database connection': database_host => 'my.postgres.host', database_username => 'mydbuser', database_password => 'mydbpassword', database_name => 'mydbname', } ### Custom Types **puppetdb_conn_validator** Verifies that a connection can be successfully established between a node and the PuppetDB server. Its primary use is as a precondition to prevent configuration changes from being applied if the PuppetDB server cannot be reached, but it could potentially be used for other purposes such as monitoring. Limitations ------------ Currently, PuppetDB is compatible with: Puppet Version: 4.10+ Platforms: * EL 5, 6, 7 * Debian 6, 7 * Ubuntu 10.04, 12.04, 14.04 Community Maintained Platforms: * Archlinux * OpenBSD 5.6-current and newer * SLES 11 SP1 Development ------------ Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. You can read the complete [contribution guide](https://github.com/puppetlabs/.github/blob/master/CONTRIBUTING.md). diff --git a/manifests/database/default_read_grant.pp b/manifests/database/default_read_grant.pp new file mode 100644 index 0000000..80d798b --- /dev/null +++ b/manifests/database/default_read_grant.pp @@ -0,0 +1,59 @@ +# Private class. Grant read permissions to $database_read_only_username by default, for new tables created by +# $database_username. +define puppetdb::database::default_read_grant( + String $database_name, + String $schema, + String $database_username, + String $database_read_only_username, +) { + postgresql_psql {"grant default select permission for ${database_read_only_username}": + db => $database_name, + command => "ALTER DEFAULT PRIVILEGES + FOR USER \"${database_username}\" + IN SCHEMA \"${schema}\" + GRANT SELECT ON TABLES + TO \"${database_read_only_username}\"", + unless => "SELECT + ns.nspname, + acl.defaclobjtype, + acl.defaclacl + FROM pg_default_acl acl + JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid + WHERE acl.defaclacl::text ~ '.*\\\\\"${database_read_only_username}\\\\\"=r/${database_username}\\\".*' + AND nspname = '${schema}'", + } + + postgresql_psql {"grant default usage permission for ${database_read_only_username}": + db => $database_name, + command => "ALTER DEFAULT PRIVILEGES + FOR USER \"${database_username}\" + IN SCHEMA \"${schema}\" + GRANT USAGE ON SEQUENCES + TO \"${database_read_only_username}\"", + unless => "SELECT + ns.nspname, + acl.defaclobjtype, + acl.defaclacl + FROM pg_default_acl acl + JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid + WHERE acl.defaclacl::text ~ '.*\\\\\"${database_read_only_username}\\\\\"=U/${database_username}\\\".*' + AND nspname = '${schema}'", + } + + postgresql_psql {"grant default execute permission for ${database_read_only_username}": + db => $database_name, + command => "ALTER DEFAULT PRIVILEGES + FOR USER \"${database_username}\" + IN SCHEMA \"${schema}\" + GRANT EXECUTE ON FUNCTIONS + TO \"${database_read_only_username}\"", + unless => "SELECT + ns.nspname, + acl.defaclobjtype, + acl.defaclacl + FROM pg_default_acl acl + JOIN pg_namespace ns ON acl.defaclnamespace=ns.oid + WHERE acl.defaclacl::text ~ '.*\\\\\"${database_read_only_username}\\\\\"=X/${database_username}\\\".*' + AND nspname = '${schema}'", + } +} diff --git a/manifests/database/postgresql.pp b/manifests/database/postgresql.pp index 0ae816c..060fff3 100644 --- a/manifests/database/postgresql.pp +++ b/manifests/database/postgresql.pp @@ -1,66 +1,103 @@ # Class for creating the PuppetDB postgresql database. See README.md for more # information. -class puppetdb::database::postgresql( +class puppetdb::database::postgresql ( $listen_addresses = $puppetdb::params::database_host, $puppetdb_server = $puppetdb::params::puppetdb_server, $database_name = $puppetdb::params::database_name, $database_username = $puppetdb::params::database_username, $database_password = $puppetdb::params::database_password, $database_port = $puppetdb::params::database_port, $manage_database = $puppetdb::params::manage_database, $manage_server = $puppetdb::params::manage_dbserver, $manage_package_repo = $puppetdb::params::manage_pg_repo, $postgres_version = $puppetdb::params::postgres_version, $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, - $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path + $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path, + $read_database_username = $puppetdb::params::read_database_username, + $read_database_password = $puppetdb::params::read_database_password, + $read_database_host = $puppetdb::params::read_database_host ) inherits puppetdb::params { if $manage_server { class { '::postgresql::globals': manage_package_repo => $manage_package_repo, version => $postgres_version, } # get the pg server up and running class { '::postgresql::server': ip_mask_allow_all_users => '0.0.0.0/0', listen_addresses => $listen_addresses, port => scanf($database_port, '%i')[0], } + # We need to create the ssl connection for the read user, when + # manage_database is set to true, or when read_database_host is defined. + # Otherwise we don't create it. + if $manage_database or $read_database_host != undef{ + $create_read_user_rule = true + } else { + $create_read_user_rule = false + } + # configure PostgreSQL communication with Puppet Agent SSL certificates if # postgresql_ssl_on is set to true if $postgresql_ssl_on { class { 'puppetdb::database::ssl_configuration': database_name => $database_name, database_username => $database_username, + read_database_username => $read_database_username, puppetdb_server => $puppetdb_server, postgresql_ssl_key_path => $postgresql_ssl_key_path, postgresql_ssl_cert_path => $postgresql_ssl_cert_path, - postgresql_ssl_ca_cert_path => $postgresql_ssl_ca_cert_path + postgresql_ssl_ca_cert_path => $postgresql_ssl_ca_cert_path, + create_read_user_rule => $create_read_user_rule } } # Only install pg_trgm extension, if database it is actually managed by the module if $manage_database { # get the pg contrib to use pg_trgm extension class { '::postgresql::server::contrib': } postgresql::server::extension { 'pg_trgm': database => $database_name, require => Postgresql::Server::Db[$database_name], } } } if $manage_database { # create the puppetdb database postgresql::server::db { $database_name: user => $database_username, password => $database_password, grant => 'all', } + + -> postgresql_psql { 'revoke all access on public schema': + db => $database_name, + command => 'REVOKE CREATE ON SCHEMA public FROM public', + unless => "SELECT * FROM + (SELECT has_schema_privilege('public', 'public', 'create') can_create) privs + WHERE privs.can_create=false", + } + + -> postgresql_psql { "grant all permissions to ${database_username}": + db => $database_name, + command => "GRANT CREATE ON SCHEMA public TO \"${database_username}\"", + unless => "SELECT * FROM + (SELECT has_schema_privilege('${database_username}', 'public', 'create') can_create) privs + WHERE privs.can_create=true", + } + + -> puppetdb::database::read_only_user { $read_database_username: + read_database_username => $read_database_username, + database_name => $database_name, + password_hash => postgresql::postgresql_password($read_database_username, $read_database_password), + database_owner => $database_username + } } -} \ No newline at end of file +} diff --git a/manifests/database/postgresql_ssl_rules.pp b/manifests/database/postgresql_ssl_rules.pp new file mode 100644 index 0000000..56b4839 --- /dev/null +++ b/manifests/database/postgresql_ssl_rules.pp @@ -0,0 +1,34 @@ +# Private class for configuring the pg_ident.conf and pg_hba.conf files +define puppetdb::database::postgresql_ssl_rules ( + String $database_name, + String $database_username, + String $puppetdb_server, +) { + $identity_map_key = "${database_name}-${database_username}-map" + + postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv4)": + type => 'hostssl', + database => $database_name, + user => $database_username, + address => '0.0.0.0/0', + auth_method => 'cert', + order => 0, + auth_option => "map=${identity_map_key} clientcert=1" + } + + postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv6)": + type => 'hostssl', + database => $database_name, + user => $database_username, + address => '::0/0', + auth_method => 'cert', + order => 0, + auth_option => "map=${identity_map_key} clientcert=1" + } + + postgresql::server::pg_ident_rule { "Map the SSL certificate of the server as a ${database_username} user": + map_name => $identity_map_key, + system_username => $puppetdb_server, + database_username => $database_username, + } +} diff --git a/manifests/database/read_grant.pp b/manifests/database/read_grant.pp new file mode 100644 index 0000000..7cbfbc6 --- /dev/null +++ b/manifests/database/read_grant.pp @@ -0,0 +1,50 @@ +# Private class. Grant read-only permissions to $database_read_only_username for all objects in $schema of +# $database_name +define puppetdb::database::read_grant ( + String $database_name, + String $schema, + String $database_read_only_username, +) { + postgresql_psql { "grant select permission for ${database_read_only_username}": + db => $database_name, + command => "GRANT SELECT + ON ALL TABLES IN SCHEMA \"${schema}\" + TO \"${database_read_only_username}\"", + unless => "SELECT * FROM ( + SELECT COUNT(*) + FROM pg_tables + WHERE schemaname='public' + AND has_table_privilege('${database_read_only_username}', schemaname || '.' || tablename, 'SELECT')=false + ) x + WHERE x.count=0", + } + + postgresql_psql { "grant usage permission for ${database_read_only_username}": + db => $database_name, + command => "GRANT USAGE + ON ALL SEQUENCES IN SCHEMA \"${schema}\" + TO \"${database_read_only_username}\"", + unless => "SELECT * FROM ( + SELECT COUNT(*) + FROM information_schema.sequences + WHERE sequence_schema='public' + AND has_sequence_privilege('${database_read_only_username}', sequence_schema || '.' || sequence_name, 'USAGE')=false + ) x + WHERE x.count=0", + } + + postgresql_psql { "grant execution permission for ${database_read_only_username}": + db => $database_name, + command => "GRANT EXECUTE + ON ALL FUNCTIONS IN SCHEMA \"${schema}\" + TO \"${database_read_only_username}\"", + unless => "SELECT * FROM ( + SELECT COUNT(*) + FROM pg_catalog.pg_proc p + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace + WHERE n.nspname='public' + AND has_function_privilege('${database_read_only_username}', p.oid, 'EXECUTE')=false + ) x + WHERE x.count=0", + } +} diff --git a/manifests/database/read_only_user.pp b/manifests/database/read_only_user.pp new file mode 100644 index 0000000..7826932 --- /dev/null +++ b/manifests/database/read_only_user.pp @@ -0,0 +1,44 @@ +# Private class +# A define type to manage the creation of a read-only postgres users. +# In particular, it manages the necessary grants to enable such a user +# to have read-only access to any existing objects as well as changes +# the default access privileges so read-only access is maintained when +# new objects are created by the $database_owner +# +# @param database_read_only_username [String] The name of the postgres read only user. +# @param database [String] The name of the database to grant access to. +# @param database_owner [String] The user which owns the database (i.e. the migration user +# for the database). +# @param password_hash [String] The value of $_database_password in app_database. + +define puppetdb::database::read_only_user ( + String $read_database_username, + String $database_name, + String $database_owner, + Variant[String, Boolean] $password_hash = false, +) { + postgresql::server::role { $read_database_username: + password_hash => $password_hash, + } + + -> postgresql::server::database_grant { "${database_name} grant connection permission to ${read_database_username}": + privilege => 'CONNECT', + db => $database_name, + role => $read_database_username, + } + + -> puppetdb::database::default_read_grant { + "${database_name} grant read permission on new objects from ${database_owner} to ${read_database_username}": + database_username => $database_owner, + database_read_only_username => $read_database_username, + database_name => $database_name, + schema => 'public', + } + + -> puppetdb::database::read_grant { + "${database_name} grant read-only permission on existing objects to ${read_database_username}": + database_read_only_username => $read_database_username, + database_name => $database_name, + schema => 'public', + } +} diff --git a/manifests/database/ssl_configuration.pp b/manifests/database/ssl_configuration.pp index 0587470..0d2473c 100644 --- a/manifests/database/ssl_configuration.pp +++ b/manifests/database/ssl_configuration.pp @@ -1,81 +1,68 @@ # Class for configuring SSL connection for the PuppetDB postgresql database. See README.md for more # information. -class puppetdb::database::ssl_configuration( +class puppetdb::database::ssl_configuration ( $database_name = $puppetdb::params::database_name, $database_username = $puppetdb::params::database_username, + $read_database_username = $puppetdb::params::read_database_username, + $read_database_host = $puppetdb::params::read_database_host, $puppetdb_server = $puppetdb::params::puppetdb_server, $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, - $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path + $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path, + $create_read_user_rule = false, ) inherits puppetdb::params { - - file {'postgres private key': + File { ensure => present, - path => "${postgresql::server::datadir}/server.key", - source => $postgresql_ssl_key_path, owner => 'postgres', mode => '0600', require => Package['postgresql-server'], } - file {'postgres public key': - ensure => present, - path => "${postgresql::server::datadir}/server.crt", - source => $postgresql_ssl_cert_path, - owner => 'postgres', - mode => '0600', - require => Package['postgresql-server'], + file { 'postgres private key': + path => "${postgresql::server::datadir}/server.key", + source => $postgresql_ssl_key_path, + } + + file { 'postgres public key': + path => "${postgresql::server::datadir}/server.crt", + source => $postgresql_ssl_cert_path, } - postgresql::server::config_entry {'ssl': + postgresql::server::config_entry { 'ssl': ensure => present, value => 'on', require => [File['postgres private key'], File['postgres public key']] } - postgresql::server::config_entry {'ssl_cert_file': + postgresql::server::config_entry { 'ssl_cert_file': ensure => present, value => "${postgresql::server::datadir}/server.crt", require => [File['postgres private key'], File['postgres public key']] } - postgresql::server::config_entry {'ssl_key_file': + postgresql::server::config_entry { 'ssl_key_file': ensure => present, value => "${postgresql::server::datadir}/server.key", require => [File['postgres private key'], File['postgres public key']] } - postgresql::server::config_entry {'ssl_ca_file': + postgresql::server::config_entry { 'ssl_ca_file': ensure => present, value => $postgresql_ssl_ca_cert_path, require => [File['postgres private key'], File['postgres public key']] } - $identity_map_key = "${database_name}-${database_username}-map" - - postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv4)": - type => 'hostssl', - database => $database_name, - user => $database_username, - address => '0.0.0.0/0', - auth_method => 'cert', - order => 0, - auth_option => "map=${identity_map_key} clientcert=1" - } - - postgresql::server::pg_hba_rule { "Allow certificate mapped connections to ${database_name} as ${database_username} (ipv6)": - type => 'hostssl', - database => $database_name, - user => $database_username, - address => '::0/0', - auth_method => 'cert', - order => 0, - auth_option => "map=${identity_map_key} clientcert=1" + puppetdb::database::postgresql_ssl_rules { "Configure postgresql ssl rules for ${database_username}": + database_name => $database_name, + database_username => $database_username, + puppetdb_server => $puppetdb_server, } - postgresql::server::pg_ident_rule {"Map the SSL certificate of the server as a ${database_username} user": - map_name => $identity_map_key, - system_username => $puppetdb_server, - database_username => $database_username, + if $create_read_user_rule { + puppetdb::database::postgresql_ssl_rules { "Configure postgresql ssl rules for ${read_database_username}": + database_name => $database_name, + database_username => $read_database_username, + puppetdb_server => $puppetdb_server, + } } } diff --git a/manifests/init.pp b/manifests/init.pp index 82a65e3..c999441 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,200 +1,207 @@ # All in one class for setting up a PuppetDB instance. See README.md for more # details. class puppetdb ( $listen_address = $puppetdb::params::listen_address, $listen_port = $puppetdb::params::listen_port, $disable_cleartext = $puppetdb::params::disable_cleartext, $open_listen_port = $puppetdb::params::open_listen_port, $ssl_listen_address = $puppetdb::params::ssl_listen_address, $ssl_listen_port = $puppetdb::params::ssl_listen_port, $disable_ssl = $puppetdb::params::disable_ssl, $open_ssl_listen_port = $puppetdb::params::open_ssl_listen_port, $ssl_dir = $puppetdb::params::ssl_dir, $ssl_set_cert_paths = $puppetdb::params::ssl_set_cert_paths, $ssl_cert_path = $puppetdb::params::ssl_cert_path, $ssl_key_path = $puppetdb::params::ssl_key_path, $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path, $ssl_deploy_certs = $puppetdb::params::ssl_deploy_certs, $ssl_key = $puppetdb::params::ssl_key, $ssl_cert = $puppetdb::params::ssl_cert, $ssl_ca_cert = $puppetdb::params::ssl_ca_cert, $ssl_protocols = $puppetdb::params::ssl_protocols, $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, $postgresql_ssl_folder = $puppetdb::params::postgresql_ssl_folder, $postgresql_ssl_cert_path = $puppetdb::params::postgresql_ssl_cert_path, $postgresql_ssl_key_path = $puppetdb::params::postgresql_ssl_key_path, $postgresql_ssl_ca_cert_path = $puppetdb::params::postgresql_ssl_ca_cert_path, $cipher_suites = $puppetdb::params::cipher_suites, $migrate = $puppetdb::params::migrate, $manage_dbserver = $puppetdb::params::manage_dbserver, $manage_database = $puppetdb::params::manage_database, $manage_package_repo = $puppetdb::params::manage_pg_repo, $postgres_version = $puppetdb::params::postgres_version, $database = $puppetdb::params::database, $database_host = $puppetdb::params::database_host, $database_port = $puppetdb::params::database_port, $database_username = $puppetdb::params::database_username, $database_password = $puppetdb::params::database_password, $database_name = $puppetdb::params::database_name, $manage_db_password = $puppetdb::params::manage_db_password, $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, $database_listen_address = $puppetdb::params::postgres_listen_addresses, $database_validate = $puppetdb::params::database_validate, $database_embedded_path = $puppetdb::params::database_embedded_path, $node_ttl = $puppetdb::params::node_ttl, $node_purge_ttl = $puppetdb::params::node_purge_ttl, $report_ttl = $puppetdb::params::report_ttl, Optional[Array] $facts_blacklist = $puppetdb::params::facts_blacklist, $gc_interval = $puppetdb::params::gc_interval, $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, $log_slow_statements = $puppetdb::params::log_slow_statements, $conn_max_age = $puppetdb::params::conn_max_age, $conn_keep_alive = $puppetdb::params::conn_keep_alive, $conn_lifetime = $puppetdb::params::conn_lifetime, $puppetdb_package = $puppetdb::params::puppetdb_package, $puppetdb_service = $puppetdb::params::puppetdb_service, $puppetdb_service_status = $puppetdb::params::puppetdb_service_status, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $puppetdb_server = $puppetdb::params::puppetdb_server, $read_database = $puppetdb::params::read_database, $read_database_host = $puppetdb::params::read_database_host, $read_database_port = $puppetdb::params::read_database_port, $read_database_username = $puppetdb::params::read_database_username, $read_database_password = $puppetdb::params::read_database_password, $read_database_name = $puppetdb::params::read_database_name, $manage_read_db_password = $puppetdb::params::manage_read_db_password, $read_database_jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, $read_database_validate = $puppetdb::params::read_database_validate, $read_log_slow_statements = $puppetdb::params::read_log_slow_statements, $read_conn_max_age = $puppetdb::params::read_conn_max_age, $read_conn_keep_alive = $puppetdb::params::read_conn_keep_alive, $read_conn_lifetime = $puppetdb::params::read_conn_lifetime, $confdir = $puppetdb::params::confdir, $vardir = $puppetdb::params::vardir, $manage_firewall = $puppetdb::params::manage_firewall, $java_args = $puppetdb::params::java_args, $merge_default_java_args = $puppetdb::params::merge_default_java_args, $max_threads = $puppetdb::params::max_threads, $command_threads = $puppetdb::params::command_threads, $concurrent_writes = $puppetdb::params::concurrent_writes, $store_usage = $puppetdb::params::store_usage, $temp_usage = $puppetdb::params::temp_usage, $disable_update_checking = $puppetdb::params::disable_update_checking, $certificate_whitelist_file = $puppetdb::params::certificate_whitelist_file, $certificate_whitelist = $puppetdb::params::certificate_whitelist, $database_max_pool_size = $puppetdb::params::database_max_pool_size, $read_database_max_pool_size = $puppetdb::params::read_database_max_pool_size, Boolean $automatic_dlo_cleanup = $puppetdb::params::automatic_dlo_cleanup, String[1] $cleanup_timer_interval = $puppetdb::params::cleanup_timer_interval, Integer[1] $dlo_max_age = $puppetdb::params::dlo_max_age, Optional[Stdlib::Absolutepath] $java_bin = $puppetdb::params::java_bin, ) inherits puppetdb::params { class { '::puppetdb::server': listen_address => $listen_address, listen_port => $listen_port, disable_cleartext => $disable_cleartext, open_listen_port => $open_listen_port, ssl_listen_address => $ssl_listen_address, ssl_listen_port => $ssl_listen_port, disable_ssl => $disable_ssl, open_ssl_listen_port => $open_ssl_listen_port, ssl_dir => $ssl_dir, ssl_set_cert_paths => $ssl_set_cert_paths, ssl_cert_path => $ssl_cert_path, ssl_key_path => $ssl_key_path, ssl_key_pk8_path => $ssl_key_pk8_path, ssl_ca_cert_path => $ssl_ca_cert_path, ssl_deploy_certs => $ssl_deploy_certs, ssl_key => $ssl_key, ssl_cert => $ssl_cert, ssl_ca_cert => $ssl_ca_cert, ssl_protocols => $ssl_protocols, postgresql_ssl_on => $postgresql_ssl_on, cipher_suites => $cipher_suites, migrate => $migrate, database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, manage_db_password => $manage_db_password, jdbc_ssl_properties => $jdbc_ssl_properties, database_validate => $database_validate, database_embedded_path => $database_embedded_path, node_ttl => $node_ttl, node_purge_ttl => $node_purge_ttl, report_ttl => $report_ttl, facts_blacklist => $facts_blacklist, gc_interval => $gc_interval, node_purge_gc_batch_limit => $node_purge_gc_batch_limit, log_slow_statements => $log_slow_statements, conn_max_age => $conn_max_age, conn_keep_alive => $conn_keep_alive, conn_lifetime => $conn_lifetime, puppetdb_package => $puppetdb_package, puppetdb_service => $puppetdb_service, puppetdb_service_status => $puppetdb_service_status, confdir => $confdir, vardir => $vardir, java_args => $java_args, merge_default_java_args => $merge_default_java_args, max_threads => $max_threads, read_database => $read_database, read_database_host => $read_database_host, read_database_port => $read_database_port, read_database_username => $read_database_username, read_database_password => $read_database_password, read_database_name => $read_database_name, manage_read_db_password => $manage_read_db_password, read_database_jdbc_ssl_properties => $read_database_jdbc_ssl_properties, read_database_validate => $read_database_validate, read_log_slow_statements => $read_log_slow_statements, read_conn_max_age => $read_conn_max_age, read_conn_keep_alive => $read_conn_keep_alive, read_conn_lifetime => $read_conn_lifetime, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, manage_firewall => $manage_firewall, + manage_database => $manage_database, command_threads => $command_threads, concurrent_writes => $concurrent_writes, store_usage => $store_usage, temp_usage => $temp_usage, disable_update_checking => $disable_update_checking, certificate_whitelist_file => $certificate_whitelist_file, certificate_whitelist => $certificate_whitelist, database_max_pool_size => $database_max_pool_size, read_database_max_pool_size => $read_database_max_pool_size, automatic_dlo_cleanup => $automatic_dlo_cleanup, cleanup_timer_interval => $cleanup_timer_interval, dlo_max_age => $dlo_max_age, java_bin => $java_bin, } if ($database == 'postgres') { $database_before = str2bool($database_validate) ? { false => Class['::puppetdb::server'], default => [Class['::puppetdb::server'], Class['::puppetdb::server::validate_db']], } class { '::puppetdb::database::postgresql': - listen_addresses => $database_listen_address, - database_name => $database_name, - puppetdb_server => $puppetdb_server, - database_username => $database_username, - database_password => $database_password, - database_port => $database_port, - manage_server => $manage_dbserver, - manage_database => $manage_database, - manage_package_repo => $manage_package_repo, - postgres_version => $postgres_version, - postgresql_ssl_on => $postgresql_ssl_on, - before => $database_before + listen_addresses => $database_listen_address, + database_name => $database_name, + puppetdb_server => $puppetdb_server, + database_username => $database_username, + database_password => $database_password, + database_port => $database_port, + manage_server => $manage_dbserver, + manage_database => $manage_database, + manage_package_repo => $manage_package_repo, + postgres_version => $postgres_version, + postgresql_ssl_on => $postgresql_ssl_on, + postgresql_ssl_key_path => $postgresql_ssl_key_path, + postgresql_ssl_cert_path => $postgresql_ssl_cert_path, + postgresql_ssl_ca_cert_path => $postgresql_ssl_ca_cert_path, + read_database_username => $read_database_username, + read_database_password => $read_database_password, + read_database_host => $read_database_host, + before => $database_before } } } diff --git a/manifests/params.pp b/manifests/params.pp index 1cd56b2..fc9b676 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,221 +1,221 @@ # PRIVATE CLASS - do not use directly # # The puppetdb default configuration settings. class puppetdb::params inherits puppetdb::globals { $listen_address = 'localhost' $listen_port = '8080' $disable_cleartext = false $open_listen_port = false $ssl_listen_address = '0.0.0.0' $ssl_listen_port = '8081' $ssl_protocols = undef $disable_ssl = false $cipher_suites = undef $open_ssl_listen_port = undef $postgres_listen_addresses = 'localhost' $puppetdb_version = $puppetdb::globals::version $database = $puppetdb::globals::database $manage_dbserver = true $manage_database = true if $::osfamily =~ /RedHat|Debian/ { $manage_pg_repo = true } else { $manage_pg_repo = false } $postgres_version = '9.6' # The remaining database settings are not used for an embedded database $database_host = 'localhost' $database_port = '5432' $database_name = 'puppetdb' $database_username = 'puppetdb' $database_password = 'puppetdb' $manage_db_password = true $jdbc_ssl_properties = '' $database_validate = true $database_max_pool_size = undef $puppetdb_server = $::fqdn # These settings manage the various auto-deactivation and auto-purge settings $node_ttl = '7d' $node_purge_ttl = '14d' $report_ttl = '14d' $facts_blacklist = undef $gc_interval = '60' $node_purge_gc_batch_limit = '25' $log_slow_statements = '10' $conn_max_age = '60' $conn_keep_alive = '45' $conn_lifetime = '0' $max_threads = undef $migrate = true # These settings are for the read database $read_database = 'postgres' $read_database_host = undef $read_database_port = '5432' $read_database_name = 'puppetdb' - $read_database_username = 'puppetdb' - $read_database_password = 'puppetdb' + $read_database_username = 'puppetdb-read' + $read_database_password = 'puppetdb-read' $manage_read_db_password = true $read_database_jdbc_ssl_properties = '' $read_database_validate = true $read_log_slow_statements = '10' $read_conn_max_age = '60' $read_conn_keep_alive = '45' $read_conn_lifetime = '0' $read_database_max_pool_size = undef $manage_firewall = true $java_args = {} $merge_default_java_args = true $puppetdb_package = 'puppetdb' $puppetdb_service = 'puppetdb' $masterless = false if !($puppetdb_version in ['latest','present','absent']) and versioncmp($puppetdb_version, '3.0.0') < 0 { case $::osfamily { 'RedHat', 'Suse', 'Archlinux','Debian': { $etcdir = '/etc/puppetdb' $vardir = '/var/lib/puppetdb' $database_embedded_path = "${vardir}/db/db" $puppet_confdir = pick($settings::confdir,'/etc/puppet') $puppet_service_name = 'puppetmaster' } 'OpenBSD': { $etcdir = '/etc/puppetdb' $vardir = '/var/db/puppetdb' $database_embedded_path = "${vardir}/db/db" $puppet_confdir = pick($settings::confdir,'/etc/puppet') $puppet_service_name = 'puppetmasterd' } 'FreeBSD': { $etcdir = '/usr/local/etc/puppetdb' $vardir = '/var/db/puppetdb' $database_embedded_path = "${vardir}/db/db" $puppet_confdir = pick($settings::confdir,'/usr/local/etc/puppet') $puppet_service_name = 'puppetmaster' } default: { fail("The fact 'osfamily' is set to ${::osfamily} which is not supported by the puppetdb module.") } } $terminus_package = 'puppetdb-terminus' $test_url = '/v3/version' } else { case $::osfamily { 'RedHat', 'Suse', 'Archlinux','Debian': { $etcdir = '/etc/puppetlabs/puppetdb' $puppet_confdir = pick($settings::confdir,'/etc/puppetlabs/puppet') $puppet_service_name = 'puppetserver' } 'OpenBSD': { $etcdir = '/etc/puppetlabs/puppetdb' $puppet_confdir = pick($settings::confdir,'/etc/puppetlabs/puppet') $puppet_service_name = undef } 'FreeBSD': { $etcdir = '/usr/local/etc/puppetlabs/puppetdb' $puppet_confdir = pick($settings::confdir,'/usr/local/etc/puppetlabs/puppet') $puppet_service_name = undef } default: { fail("The fact 'osfamily' is set to ${::osfamily} which is not supported by the puppetdb module.") } } $terminus_package = 'puppetdb-termini' $test_url = '/pdb/meta/v1/version' $vardir = '/opt/puppetlabs/server/data/puppetdb' $database_embedded_path = "${vardir}/db/db" } $confdir = "${etcdir}/conf.d" $ssl_dir = "${etcdir}/ssl" case $::osfamily { 'RedHat', 'Suse', 'Archlinux': { $puppetdb_user = 'puppetdb' $puppetdb_group = 'puppetdb' $puppetdb_initconf = '/etc/sysconfig/puppetdb' } 'Debian': { $puppetdb_user = 'puppetdb' $puppetdb_group = 'puppetdb' $puppetdb_initconf = '/etc/default/puppetdb' } 'OpenBSD': { $puppetdb_user = '_puppetdb' $puppetdb_group = '_puppetdb' $puppetdb_initconf = undef } 'FreeBSD': { $puppetdb_user = 'puppetdb' $puppetdb_group = 'puppetdb' $puppetdb_initconf = undef } default: { fail("The fact 'osfamily' is set to ${::osfamily} which is not supported by the puppetdb module.") } } $puppet_conf = "${puppet_confdir}/puppet.conf" $puppetdb_startup_timeout = 120 $puppetdb_service_status = 'running' $command_threads = undef $concurrent_writes = undef $store_usage = undef $temp_usage = undef $disable_update_checking = undef # reports of failed actions: https://puppet.com/docs/puppetdb/5.2/maintain_and_tune.html#clean-up-the-dead-letter-office $automatic_dlo_cleanup = true # any value for a systemd timer is valid: https://www.freedesktop.org/software/systemd/man/systemd.time.html $cleanup_timer_interval = "*-*-* ${fqdn_rand(24)}:${fqdn_rand(60)}:00" $dlo_max_age = 90 # certificats used for PostgreSQL SSL configuration. Puppet certificates are used $postgresql_ssl_on = false $postgresql_ssl_folder = "${puppet_confdir}/ssl" $postgresql_ssl_cert_path = "${postgresql_ssl_folder}/certs/${trusted['certname']}.pem" $postgresql_ssl_key_path = "${postgresql_ssl_folder}/private_keys/${trusted['certname']}.pem" $postgresql_ssl_ca_cert_path = "${postgresql_ssl_folder}/certs/ca.pem" # certificats used for Jetty configuration $ssl_set_cert_paths = false $ssl_cert_path = "${ssl_dir}/public.pem" $ssl_key_path = "${ssl_dir}/private.pem" $ssl_ca_cert_path = "${ssl_dir}/ca.pem" $ssl_deploy_certs = false $ssl_key = undef $ssl_cert = undef $ssl_ca_cert = undef # certificate used by PuppetDB SSL Configuration $ssl_key_pk8_path = regsubst($ssl_key_path, '.pem', '.pk8') $certificate_whitelist_file = "${etcdir}/certificate-whitelist" # the default is free access for now $certificate_whitelist = [ ] # change to this to only allow access by the puppet master by default: #$certificate_whitelist = [ $::servername ] # Get the parameter name for the database connection pool tuning if $puppetdb_version in ['latest','present'] or versioncmp($puppetdb_version, '4.0.0') >= 0 { $database_max_pool_size_setting_name = 'maximum-pool-size' } elsif versioncmp($puppetdb_version, '2.8.0') >= 0 { $database_max_pool_size_setting_name = 'partition-conn-max' } else { $database_max_pool_size_setting_name = undef } # java binary path for PuppetDB. If undef, default will be used. $java_bin = undef } diff --git a/manifests/server.pp b/manifests/server.pp index 09823dc..8fd4bd9 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,400 +1,411 @@ # Class to configure a PuppetDB server. See README.md for more details. class puppetdb::server ( $listen_address = $puppetdb::params::listen_address, $listen_port = $puppetdb::params::listen_port, $disable_cleartext = $puppetdb::params::disable_cleartext, $open_listen_port = $puppetdb::params::open_listen_port, $ssl_listen_address = $puppetdb::params::ssl_listen_address, $ssl_listen_port = $puppetdb::params::ssl_listen_port, $disable_ssl = $puppetdb::params::disable_ssl, $open_ssl_listen_port = $puppetdb::params::open_ssl_listen_port, Stdlib::Absolutepath $ssl_dir = $puppetdb::params::ssl_dir, Boolean $ssl_set_cert_paths = $puppetdb::params::ssl_set_cert_paths, Stdlib::Absolutepath $ssl_cert_path = $puppetdb::params::ssl_cert_path, Stdlib::Absolutepath $ssl_key_path = $puppetdb::params::ssl_key_path, Stdlib::Absolutepath $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, Stdlib::Absolutepath $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path, Boolean $ssl_deploy_certs = $puppetdb::params::ssl_deploy_certs, $ssl_key = $puppetdb::params::ssl_key, $ssl_cert = $puppetdb::params::ssl_cert, $ssl_ca_cert = $puppetdb::params::ssl_ca_cert, $ssl_protocols = $puppetdb::params::ssl_protocols, $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, $cipher_suites = $puppetdb::params::cipher_suites, $migrate = $puppetdb::params::migrate, $database = $puppetdb::params::database, $database_host = $puppetdb::params::database_host, $database_port = $puppetdb::params::database_port, $database_username = $puppetdb::params::database_username, $database_password = $puppetdb::params::database_password, $database_name = $puppetdb::params::database_name, $manage_db_password = $puppetdb::params::manage_db_password, $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, $database_validate = $puppetdb::params::database_validate, $database_embedded_path = $puppetdb::params::database_embedded_path, $node_ttl = $puppetdb::params::node_ttl, $node_purge_ttl = $puppetdb::params::node_purge_ttl, $report_ttl = $puppetdb::params::report_ttl, Optional[Array] $facts_blacklist = $puppetdb::params::facts_blacklist, $gc_interval = $puppetdb::params::gc_interval, $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, $log_slow_statements = $puppetdb::params::log_slow_statements, $conn_max_age = $puppetdb::params::conn_max_age, $conn_keep_alive = $puppetdb::params::conn_keep_alive, $conn_lifetime = $puppetdb::params::conn_lifetime, $puppetdb_package = $puppetdb::params::puppetdb_package, $puppetdb_service = $puppetdb::params::puppetdb_service, $puppetdb_service_status = $puppetdb::params::puppetdb_service_status, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $read_database = $puppetdb::params::read_database, $read_database_host = $puppetdb::params::read_database_host, $read_database_port = $puppetdb::params::read_database_port, $read_database_username = $puppetdb::params::read_database_username, $read_database_password = $puppetdb::params::read_database_password, $read_database_name = $puppetdb::params::read_database_name, $manage_read_db_password = $puppetdb::params::manage_read_db_password, $read_database_jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, $read_database_validate = $puppetdb::params::read_database_validate, $read_log_slow_statements = $puppetdb::params::read_log_slow_statements, $read_conn_max_age = $puppetdb::params::read_conn_max_age, $read_conn_keep_alive = $puppetdb::params::read_conn_keep_alive, $read_conn_lifetime = $puppetdb::params::read_conn_lifetime, $confdir = $puppetdb::params::confdir, $vardir = $puppetdb::params::vardir, $manage_firewall = $puppetdb::params::manage_firewall, + $manage_database = $puppetdb::params::manage_database, $java_args = $puppetdb::params::java_args, $merge_default_java_args = $puppetdb::params::merge_default_java_args, $max_threads = $puppetdb::params::max_threads, $command_threads = $puppetdb::params::command_threads, $concurrent_writes = $puppetdb::params::concurrent_writes, $store_usage = $puppetdb::params::store_usage, $temp_usage = $puppetdb::params::temp_usage, $disable_update_checking = $puppetdb::params::disable_update_checking, $certificate_whitelist_file = $puppetdb::params::certificate_whitelist_file, $certificate_whitelist = $puppetdb::params::certificate_whitelist, $database_max_pool_size = $puppetdb::params::database_max_pool_size, $read_database_max_pool_size = $puppetdb::params::read_database_max_pool_size, Boolean $automatic_dlo_cleanup = $puppetdb::params::automatic_dlo_cleanup, String[1] $cleanup_timer_interval = $puppetdb::params::cleanup_timer_interval, Integer[1] $dlo_max_age = $puppetdb::params::dlo_max_age, Optional[Stdlib::Absolutepath] $java_bin = $puppetdb::params::java_bin, ) inherits puppetdb::params { # Apply necessary suffix if zero is specified. # Can we drop this in the next major release? if $node_ttl == '0' { $_node_ttl_real = '0s' } else { $_node_ttl_real = downcase($node_ttl) } # Validate node_ttl $node_ttl_real = assert_type(Puppetdb::Ttl, $_node_ttl_real) # Apply necessary suffix if zero is specified. # Can we drop this in the next major release? if $node_purge_ttl == '0' { $_node_purge_ttl_real = '0s' } else { $_node_purge_ttl_real = downcase($node_purge_ttl) } # Validate node_purge_ttl $node_purge_ttl_real = assert_type(Puppetdb::Ttl, $_node_purge_ttl_real) # Apply necessary suffix if zero is specified. # Can we drop this in the next major release? if $report_ttl == '0' { $_report_ttl_real = '0s' } else { $_report_ttl_real = downcase($report_ttl) } # Validate report_ttl $repor_ttl_real = assert_type(Puppetdb::Ttl, $_report_ttl_real) # Validate puppetdb_service_status $service_enabled = $puppetdb_service_status ? { /(running|true)/ => true, /(stopped|false)/ => false, default => fail("puppetdb_service_status valid values are 'true', 'running', 'false', and 'stopped'. You provided '${puppetdb_service_status}'"), } # Validate database type (Currently only postgres and embedded are supported) if !($database in ['postgres', 'embedded']) { fail("database must must be 'postgres' or 'embedded'. You provided '${database}'") } # Validate read-database type (Currently only postgres is supported) if !($read_database in ['postgres']) { fail("read_database must be 'postgres'. You provided '${read_database}'") } package { $puppetdb_package: ensure => $puppetdb::params::puppetdb_version, notify => Service[$puppetdb_service], } if $manage_firewall { class { 'puppetdb::server::firewall': http_port => $listen_port, open_http_port => $open_listen_port, ssl_port => $ssl_listen_port, open_ssl_port => $open_ssl_listen_port, } } class { 'puppetdb::server::global': vardir => $vardir, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, notify => Service[$puppetdb_service], } class { 'puppetdb::server::command_processing': command_threads => $command_threads, concurrent_writes => $concurrent_writes, store_usage => $store_usage, temp_usage => $temp_usage, confdir => $confdir, notify => Service[$puppetdb_service], } class { 'puppetdb::server::database': database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, manage_db_password => $manage_db_password, postgresql_ssl_on => $postgresql_ssl_on, ssl_key_pk8_path => $ssl_key_pk8_path, ssl_cert_path => $ssl_cert_path, ssl_ca_cert_path => $ssl_ca_cert_path, database_max_pool_size => $database_max_pool_size, jdbc_ssl_properties => $jdbc_ssl_properties, database_validate => $database_validate, database_embedded_path => $database_embedded_path, node_ttl => $node_ttl, node_purge_ttl => $node_purge_ttl, report_ttl => $report_ttl, facts_blacklist => $facts_blacklist, gc_interval => $gc_interval, node_purge_gc_batch_limit => $node_purge_gc_batch_limit, log_slow_statements => $log_slow_statements, conn_max_age => $conn_max_age, conn_keep_alive => $conn_keep_alive, conn_lifetime => $conn_lifetime, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, migrate => $migrate, notify => Service[$puppetdb_service], } + if $manage_database and $read_database_host == undef { + $real_database_host = $database_host + $real_database_port = $database_port + $real_database_name = $database_name + } else { + $real_database_host = $read_database_host + $real_database_port = $read_database_port + $real_database_name = $read_database_name + } + class { 'puppetdb::server::read_database': - database => $read_database, - database_host => $read_database_host, - database_port => $read_database_port, - database_username => $read_database_username, - database_password => $read_database_password, - database_name => $read_database_name, + read_database => $read_database, + read_database_host => $real_database_host, + read_database_port => $real_database_port, + read_database_username => $read_database_username, + read_database_password => $read_database_password, + read_database_name => $real_database_name, manage_db_password => $manage_read_db_password, postgresql_ssl_on => $postgresql_ssl_on, ssl_key_pk8_path => $ssl_key_pk8_path, ssl_cert_path => $ssl_cert_path, ssl_ca_cert_path => $ssl_ca_cert_path, jdbc_ssl_properties => $read_database_jdbc_ssl_properties, database_validate => $read_database_validate, log_slow_statements => $read_log_slow_statements, conn_max_age => $read_conn_max_age, conn_keep_alive => $read_conn_keep_alive, conn_lifetime => $read_conn_lifetime, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, notify => Service[$puppetdb_service], database_max_pool_size => $read_database_max_pool_size, } if $ssl_deploy_certs { file { $ssl_dir: ensure => directory, owner => $puppetdb_user, group => $puppetdb_group, mode => '0700'; $ssl_key_path: ensure => file, content => $ssl_key, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service]; $ssl_cert_path: ensure => file, content => $ssl_cert, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service]; $ssl_ca_cert_path: ensure => file, content => $ssl_ca_cert, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service]; } } if $postgresql_ssl_on { exec { $ssl_key_pk8_path: path => [ '/opt/puppetlabs/puppet/bin', $facts['path'] ], command => "openssl pkcs8 -topk8 -inform PEM -outform DER -in ${ssl_key_path} -out ${ssl_key_pk8_path} -nocrypt", # Generate a .pk8 key if one doesn't exist or is older than the .pem input. # NOTE: bash file time checks, like -ot, can't always discern sub-second # differences. onlyif => "test ! -e '${ssl_key_pk8_path}' -o '${ssl_key_pk8_path}' -ot '${ssl_key_path}'", before => File[$ssl_key_pk8_path] } file { $ssl_key_pk8_path: ensure => present, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', notify => Service[$puppetdb_service] } } class { 'puppetdb::server::jetty': listen_address => $listen_address, listen_port => $listen_port, disable_cleartext => $disable_cleartext, ssl_listen_address => $ssl_listen_address, ssl_listen_port => $ssl_listen_port, ssl_set_cert_paths => $ssl_set_cert_paths, ssl_key_path => $ssl_key_path, ssl_cert_path => $ssl_cert_path, ssl_ca_cert_path => $ssl_ca_cert_path, ssl_protocols => $ssl_protocols, cipher_suites => $cipher_suites, disable_ssl => $disable_ssl, confdir => $confdir, max_threads => $max_threads, notify => Service[$puppetdb_service], puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, } class { 'puppetdb::server::puppetdb': certificate_whitelist_file => $certificate_whitelist_file, certificate_whitelist => $certificate_whitelist, disable_update_checking => $disable_update_checking, confdir => $confdir, puppetdb_user => $puppetdb_user, puppetdb_group => $puppetdb_group, notify => Service[$puppetdb_service], } if !empty($java_args) { if $merge_default_java_args { create_resources( 'ini_subsetting', puppetdb::create_subsetting_resource_hash( $java_args, { ensure => present, section => '', key_val_separator => '=', path => $puppetdb::params::puppetdb_initconf, setting => 'JAVA_ARGS', require => Package[$puppetdb_package], notify => Service[$puppetdb_service], })) } else { ini_setting { 'java_args': ensure => present, section => '', path => $puppetdb::params::puppetdb_initconf, setting => 'JAVA_ARGS', require => Package[$puppetdb_package], notify => Service[$puppetdb_service], value => puppetdb::flatten_java_args($java_args), } } } # java binary path for PuppetDB. If undef, default will be used. if $java_bin { - ini_setting{'java': + ini_setting { 'java': ensure => 'present', section => '', path => $puppetdb::params::puppetdb_initconf, setting => 'JAVA_BIN', require => Package[$puppetdb_package], notify => Service[$puppetdb_service], value => $java_bin, } } if $automatic_dlo_cleanup { if $facts['systemd'] { # deploy a systemd timer + service to cleanup old reports # https://puppet.com/docs/puppetdb/5.2/maintain_and_tune.html#clean-up-the-dead-letter-office - systemd::unit_file{'puppetdb-dlo-cleanup.service': + systemd::unit_file { 'puppetdb-dlo-cleanup.service': content => epp("${module_name}/puppetdb-DLO-cleanup.service.epp", { 'puppetdb_user' => $puppetdb_user, 'puppetdb_group' => $puppetdb_group, 'vardir' => $vardir, 'dlo_max_age' => $dlo_max_age }), } - -> systemd::unit_file{'puppetdb-dlo-cleanup.timer': - content => epp("${module_name}/puppetdb-DLO-cleanup.timer.epp", {'cleanup_timer_interval' => $cleanup_timer_interval}), + -> systemd::unit_file { 'puppetdb-dlo-cleanup.timer': + content => epp("${module_name}/puppetdb-DLO-cleanup.timer.epp", {'cleanup_timer_interval' => $cleanup_timer_interval }), enable => true, active => true, } } else { cron { 'puppetdb-dlo-cleanup': ensure => 'present', minute => fqdn_rand(60), hour => fqdn_rand(24), monthday => '*', month => '*', weekday => '*', command => "/usr/bin/find ${vardir}/stockpile/discard/ -type f -mtime ${dlo_max_age} -delete", user => $puppetdb_user, } } } service { $puppetdb_service: ensure => $puppetdb_service_status, enable => $service_enabled, } if $manage_firewall { Package[$puppetdb_package] -> Class['puppetdb::server::firewall'] -> Class['puppetdb::server::global'] -> Class['puppetdb::server::command_processing'] -> Class['puppetdb::server::database'] -> Class['puppetdb::server::read_database'] -> Class['puppetdb::server::jetty'] -> Class['puppetdb::server::puppetdb'] -> Service[$puppetdb_service] } else { Package[$puppetdb_package] -> Class['puppetdb::server::global'] -> Class['puppetdb::server::command_processing'] -> Class['puppetdb::server::database'] -> Class['puppetdb::server::read_database'] -> Class['puppetdb::server::jetty'] -> Class['puppetdb::server::puppetdb'] -> Service[$puppetdb_service] } } diff --git a/manifests/server/database.pp b/manifests/server/database.pp index 1ba0234..12dff9f 100644 --- a/manifests/server/database.pp +++ b/manifests/server/database.pp @@ -1,221 +1,220 @@ # PRIVATE CLASS - do not use directly class puppetdb::server::database ( - $database = $puppetdb::params::database, - $database_host = $puppetdb::params::database_host, - $database_port = $puppetdb::params::database_port, - $database_username = $puppetdb::params::database_username, - $database_password = $puppetdb::params::database_password, - $database_name = $puppetdb::params::database_name, - $manage_db_password = $puppetdb::params::manage_db_password, - $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, - $database_validate = $puppetdb::params::database_validate, - $database_embedded_path = $puppetdb::params::database_embedded_path, - $node_ttl = $puppetdb::params::node_ttl, - $node_purge_ttl = $puppetdb::params::node_purge_ttl, - $report_ttl = $puppetdb::params::report_ttl, - $facts_blacklist = $puppetdb::params::facts_blacklist, - $gc_interval = $puppetdb::params::gc_interval, - $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, - $log_slow_statements = $puppetdb::params::log_slow_statements, - $conn_max_age = $puppetdb::params::conn_max_age, - $conn_keep_alive = $puppetdb::params::conn_keep_alive, - $conn_lifetime = $puppetdb::params::conn_lifetime, - $confdir = $puppetdb::params::confdir, - $puppetdb_user = $puppetdb::params::puppetdb_user, - $puppetdb_group = $puppetdb::params::puppetdb_group, - $database_max_pool_size = $puppetdb::params::database_max_pool_size, - $migrate = $puppetdb::params::migrate, - $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, - $ssl_cert_path = $puppetdb::params::ssl_cert_path, - $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, - $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path + $database = $puppetdb::params::database, + $database_host = $puppetdb::params::database_host, + $database_port = $puppetdb::params::database_port, + $database_username = $puppetdb::params::database_username, + $database_password = $puppetdb::params::database_password, + $database_name = $puppetdb::params::database_name, + $manage_db_password = $puppetdb::params::manage_db_password, + $jdbc_ssl_properties = $puppetdb::params::jdbc_ssl_properties, + $database_validate = $puppetdb::params::database_validate, + $database_embedded_path = $puppetdb::params::database_embedded_path, + $node_ttl = $puppetdb::params::node_ttl, + $node_purge_ttl = $puppetdb::params::node_purge_ttl, + $report_ttl = $puppetdb::params::report_ttl, + $facts_blacklist = $puppetdb::params::facts_blacklist, + $gc_interval = $puppetdb::params::gc_interval, + $node_purge_gc_batch_limit = $puppetdb::params::node_purge_gc_batch_limit, + $log_slow_statements = $puppetdb::params::log_slow_statements, + $conn_max_age = $puppetdb::params::conn_max_age, + $conn_keep_alive = $puppetdb::params::conn_keep_alive, + $conn_lifetime = $puppetdb::params::conn_lifetime, + $confdir = $puppetdb::params::confdir, + $puppetdb_user = $puppetdb::params::puppetdb_user, + $puppetdb_group = $puppetdb::params::puppetdb_group, + $database_max_pool_size = $puppetdb::params::database_max_pool_size, + $migrate = $puppetdb::params::migrate, + $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, + $ssl_cert_path = $puppetdb::params::ssl_cert_path, + $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, + $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path ) inherits puppetdb::params { if str2bool($database_validate) { # Validate the database connection. If we can't connect, we want to fail # and skip the rest of the configuration, so that we don't leave puppetdb # in a broken state. # # NOTE: # Because of a limitation in the postgres module this will break with # a duplicate declaration if read and write database host+name are the # same. class { 'puppetdb::server::validate_db': database => $database, database_host => $database_host, database_port => $database_port, database_username => $database_username, database_password => $database_password, database_name => $database_name, } } $database_ini = "${confdir}/database.ini" file { $database_ini: ensure => file, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', } $file_require = File[$database_ini] $ini_setting_require = str2bool($database_validate) ? { - false => $file_require, - default => [$file_require, Class['puppetdb::server::validate_db']], + false => $file_require, + default => [$file_require, Class['puppetdb::server::validate_db']], } # Set the defaults Ini_setting { path => $database_ini, ensure => present, section => 'database', require => $ini_setting_require } if $database == 'embedded' { - $classname = 'org.hsqldb.jdbcDriver' + $classname = 'org.hsqldb.jdbcDriver' $subprotocol = 'hsqldb' - $subname = "file:${database_embedded_path};hsqldb.tx=mvcc;sql.syntax_pgs=true" + $subname = "file:${database_embedded_path};hsqldb.tx=mvcc;sql.syntax_pgs=true" } elsif $database == 'postgres' { $classname = 'org.postgresql.Driver' $subprotocol = 'postgresql' if !empty($jdbc_ssl_properties) { $database_suffix = $jdbc_ssl_properties } else { $database_suffix = '' } $subname_default = "//${database_host}:${database_port}/${database_name}${database_suffix}" if $postgresql_ssl_on and !empty($jdbc_ssl_properties) { fail("Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!") } if $postgresql_ssl_on { $subname = @("EOT"/L) ${subname_default}?\ ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ | EOT } else { $subname = $subname_default } ##Only setup for postgres - ini_setting {'puppetdb_psdatabase_username': + ini_setting { 'puppetdb_psdatabase_username': setting => 'username', value => $database_username, } if $database_password != undef and $manage_db_password { - ini_setting {'puppetdb_psdatabase_password': + ini_setting { 'puppetdb_psdatabase_password': setting => 'password', value => $database_password, } } } ini_setting { 'puppetdb_classname': setting => 'classname', value => $classname, } ini_setting { 'puppetdb_subprotocol': setting => 'subprotocol', value => $subprotocol, } ini_setting { 'puppetdb_pgs': setting => 'syntax_pgs', value => true, } ini_setting { 'puppetdb_subname': setting => 'subname', value => $subname, } ini_setting { 'puppetdb_gc_interval': setting => 'gc-interval', value => $gc_interval, } ini_setting { 'puppetdb_node_purge_gc_batch_limit': setting => 'node-purge-gc-batch-limit', value => $node_purge_gc_batch_limit, } ini_setting { 'puppetdb_node_ttl': setting => 'node-ttl', value => $node_ttl, } ini_setting { 'puppetdb_node_purge_ttl': setting => 'node-purge-ttl', value => $node_purge_ttl, } ini_setting { 'puppetdb_report_ttl': setting => 'report-ttl', value => $report_ttl, } ini_setting { 'puppetdb_log_slow_statements': setting => 'log-slow-statements', value => $log_slow_statements, } ini_setting { 'puppetdb_conn_max_age': setting => 'conn-max-age', value => $conn_max_age, } ini_setting { 'puppetdb_conn_keep_alive': setting => 'conn-keep-alive', value => $conn_keep_alive, } ini_setting { 'puppetdb_conn_lifetime': setting => 'conn-lifetime', value => $conn_lifetime, } ini_setting { 'puppetdb_migrate': setting => 'migrate', value => $migrate, } if $puppetdb::params::database_max_pool_size_setting_name != undef { if $database_max_pool_size == 'absent' { ini_setting { 'puppetdb_database_max_pool_size': ensure => absent, setting => $puppetdb::params::database_max_pool_size_setting_name, } } elsif $database_max_pool_size != undef { ini_setting { 'puppetdb_database_max_pool_size': setting => $puppetdb::params::database_max_pool_size_setting_name, value => $database_max_pool_size, } } } if ($facts_blacklist) and length($facts_blacklist) != 0 { $joined_facts_blacklist = join($facts_blacklist, ', ') ini_setting { 'puppetdb_facts_blacklist': setting => 'facts-blacklist', value => $joined_facts_blacklist, } } else { ini_setting { 'puppetdb_facts_blacklist': ensure => absent, setting => 'facts-blacklist', } } - } diff --git a/manifests/server/read_database.pp b/manifests/server/read_database.pp index 093627e..688a74f 100644 --- a/manifests/server/read_database.pp +++ b/manifests/server/read_database.pp @@ -1,169 +1,172 @@ # PRIVATE CLASS - do not use directly class puppetdb::server::read_database ( - $database = $puppetdb::params::read_database, - $database_host = $puppetdb::params::read_database_host, - $database_port = $puppetdb::params::read_database_port, - $database_username = $puppetdb::params::read_database_username, - $database_password = $puppetdb::params::read_database_password, - $database_name = $puppetdb::params::read_database_name, + $read_database = $puppetdb::params::read_database, + $read_database_host = $puppetdb::params::read_database_host, + $read_database_port = $puppetdb::params::read_database_port, + $read_database_username = $puppetdb::params::read_database_username, + $read_database_password = $puppetdb::params::read_database_password, + $read_database_name = $puppetdb::params::read_database_name, $manage_db_password = $puppetdb::params::manage_read_db_password, $jdbc_ssl_properties = $puppetdb::params::read_database_jdbc_ssl_properties, $database_validate = $puppetdb::params::read_database_validate, $log_slow_statements = $puppetdb::params::read_log_slow_statements, $conn_max_age = $puppetdb::params::read_conn_max_age, $conn_keep_alive = $puppetdb::params::read_conn_keep_alive, $conn_lifetime = $puppetdb::params::read_conn_lifetime, $confdir = $puppetdb::params::confdir, $puppetdb_user = $puppetdb::params::puppetdb_user, $puppetdb_group = $puppetdb::params::puppetdb_group, $database_max_pool_size = $puppetdb::params::read_database_max_pool_size, $postgresql_ssl_on = $puppetdb::params::postgresql_ssl_on, $ssl_cert_path = $puppetdb::params::ssl_cert_path, $ssl_key_pk8_path = $puppetdb::params::ssl_key_pk8_path, $ssl_ca_cert_path = $puppetdb::params::ssl_ca_cert_path ) inherits puppetdb::params { - # Only add the read database configuration if database host is defined. - if $database_host != undef { + if $read_database_host != undef { if str2bool($database_validate) { # Validate the database connection. If we can't connect, we want to fail # and skip the rest of the configuration, so that we don't leave puppetdb # in a broken state. # # NOTE: # Because of a limitation in the postgres module this will break with # a duplicate declaration if read and write database host+name are the # same. class { 'puppetdb::server::validate_read_db': - database => $database, - database_host => $database_host, - database_port => $database_port, - database_username => $database_username, - database_password => $database_password, - database_name => $database_name, + database => $read_database, + database_host => $read_database_host, + database_port => $read_database_port, + database_username => $read_database_username, + database_password => $read_database_password, + database_name => $read_database_name, } } $read_database_ini = "${confdir}/read_database.ini" file { $read_database_ini: ensure => file, owner => $puppetdb_user, group => $puppetdb_group, mode => '0600', } $file_require = File[$read_database_ini] $ini_setting_require = str2bool($database_validate) ? { false => $file_require, default => [$file_require, Class['puppetdb::server::validate_read_db']], } # Set the defaults Ini_setting { path => $read_database_ini, ensure => present, section => 'read-database', require => $ini_setting_require, } - if $database == 'postgres' { + if $read_database == 'postgres' { $classname = 'org.postgresql.Driver' $subprotocol = 'postgresql' if !empty($jdbc_ssl_properties) { $database_suffix = $jdbc_ssl_properties } else { $database_suffix = '' } - $subname_default = "//${database_host}:${database_port}/${database_name}${database_suffix}" + $subname_default = "//${read_database_host}:${read_database_port}/${read_database_name}${database_suffix}" if $postgresql_ssl_on and !empty($jdbc_ssl_properties) { fail("Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!") } if $postgresql_ssl_on { $subname = @("EOT"/L) - ${subname_default}?\ - ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ - sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ - sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ - | EOT + ${subname_default}?\ + ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&\ + sslmode=verify-full&sslrootcert=${ssl_ca_cert_path}&\ + sslkey=${ssl_key_pk8_path}&sslcert=${ssl_cert_path}\ + | EOT } else { $subname = $subname_default } ini_setting { 'puppetdb_read_database_username': setting => 'username', - value => $database_username, + value => $read_database_username, } - if $database_password != undef and $manage_db_password { + if $read_database_password != undef and $manage_db_password { ini_setting { 'puppetdb_read_database_password': setting => 'password', - value => $database_password, + value => $read_database_password, } } } ini_setting { 'puppetdb_read_classname': setting => 'classname', value => $classname, } ini_setting { 'puppetdb_read_subprotocol': setting => 'subprotocol', value => $subprotocol, } ini_setting { 'puppetdb_read_pgs': setting => 'syntax_pgs', value => true, } ini_setting { 'puppetdb_read_subname': setting => 'subname', value => $subname, } ini_setting { 'puppetdb_read_log_slow_statements': setting => 'log-slow-statements', value => $log_slow_statements, } ini_setting { 'puppetdb_read_conn_max_age': setting => 'conn-max-age', value => $conn_max_age, } ini_setting { 'puppetdb_read_conn_keep_alive': setting => 'conn-keep-alive', value => $conn_keep_alive, } ini_setting { 'puppetdb_read_conn_lifetime': setting => 'conn-lifetime', value => $conn_lifetime, } if $puppetdb::params::database_max_pool_size_setting_name != undef { if $database_max_pool_size == 'absent' { ini_setting { 'puppetdb_read_database_max_pool_size': ensure => absent, setting => $puppetdb::params::database_max_pool_size_setting_name, } } elsif $database_max_pool_size != undef { ini_setting { 'puppetdb_read_database_max_pool_size': setting => $puppetdb::params::database_max_pool_size_setting_name, value => $database_max_pool_size, } } + } else { + file { "${confdir}/read_database.ini": + ensure => absent, + } } } else { file { "${confdir}/read_database.ini": ensure => absent, } } } diff --git a/spec/acceptance/basic_spec.rb b/spec/acceptance/basic_spec.rb index 57e2779..1b0ae50 100644 --- a/spec/acceptance/basic_spec.rb +++ b/spec/acceptance/basic_spec.rb @@ -1,80 +1,99 @@ require 'beaker-puppet' require 'beaker-pe' require 'spec_helper_acceptance' describe 'basic tests:' do it 'make sure we have copied the module across' do # No point diagnosing any more if the module wasn't copied properly shell('ls /etc/puppetlabs/code/modules/puppetdb') do |r| r.exit_code.should be_zero r.stdout.should =~ %r{metadata\.json} r.stderr.should == '' end end describe 'single node setup' do pp = <<-EOS # Single node setup class { 'puppetdb': disable_ssl => true, } -> class { 'puppetdb::master::config': puppetdb_port => '8080', puppetdb_server => 'localhost' } EOS it 'make sure it runs without error' do apply_manifest(pp, catch_errors: true) apply_manifest(pp, catch_changes: true) end end describe 'single node with ssl' do ssl_config = <<-EOS class { 'puppetdb': postgresql_ssl_on => true, database_listen_address => '0.0.0.0', database_host => $facts['fqdn'],} EOS it 'make sure it runs without error' do apply_manifest(ssl_config, catch_errors: true) apply_manifest(ssl_config, catch_changes: true) end change_password = <<-EOS ini_setting { "puppetdb password": ensure => present, path => '/etc/puppetlabs/puppetdb/conf.d/database.ini', section => 'database', setting => 'password', value => 'random_password', notify => Service[puppetdb] } service { 'puppetdb': ensure => 'running', } EOS it 'make sure it starts with wrong password' do apply_manifest(change_password, catch_errors: true) apply_manifest(change_password, catch_changes: true) end end describe 'enabling report processor' do pp = <<-EOS class { 'puppetdb': disable_ssl => true, } -> class { 'puppetdb::master::config': puppetdb_port => '8080', manage_report_processor => true, enable_reports => true, puppetdb_server => 'localhost' } EOS it 'adds the puppetdb report processor to puppet.conf' do apply_manifest(pp, catch_errors: true) apply_manifest(pp, catch_changes: true) shell('cat /etc/puppetlabs/puppet/puppet.conf') do |r| expect(r.stdout).to match(%r{^reports\s*=\s*([^,]+,)*puppetdb(,[^,]+)*$}) end end end + + describe 'read only user' do + pp = <<-EOS + class { 'puppetdb': disable_ssl => true, } -> + class { 'puppetdb::master::config': + puppetdb_port => '8080', + puppetdb_server => 'localhost' + } + EOS + + it 'can not create tables' do + apply_manifest(pp, catch_errors: true) + apply_manifest(pp, catch_changes: true) + + shell('psql "postgresql://puppetdb-read:puppetdb-read@localhost/puppetdb" -c "create table tables(id int);"') do |r| + expect(r.stdout).to match(%r{^ERROR: permission denied for schema public.*}) + end + end + end end diff --git a/spec/unit/classes/database/ssl_configuration_spec.rb b/spec/unit/classes/database/ssl_configuration_spec.rb index 1a42faa..b5620df 100644 --- a/spec/unit/classes/database/ssl_configuration_spec.rb +++ b/spec/unit/classes/database/ssl_configuration_spec.rb @@ -1,139 +1,192 @@ require 'spec_helper' describe 'puppetdb::database::ssl_configuration', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', puppetversion: Puppet.version, operatingsystemrelease: '7.0', kernel: 'Linux', selinux: true, os: { family: 'RedHat', name: 'RedHat', release: { 'full' => '7.0', 'major' => '7' }, selinux: { 'enabled' => true }, }, fqdn: 'cheery-rime@puppet', } end let(:params) do { postgresql_ssl_key_path: '/puppet/ssl/key.pem', postgresql_ssl_cert_path: '/puppet/ssl/cert.pem', postgresql_ssl_ca_cert_path: '/puppet/cert/ca.pem', database_name: 'puppetdb', database_username: 'puppetdb', + read_database_username: 'puppetdb-read', } end let(:identity_map) { "#{params[:database_name]}-#{params[:database_username]}-map" } + let(:read_identity_map) { "#{params[:database_name]}-#{params[:read_database_username]}-map" } let(:datadir_path) { '/var/lib/data' } let(:pre_condition) do "class { 'postgresql::server': datadir => '/var/lib/data'} " end it { is_expected.to contain_class('puppetdb::database::ssl_configuration') } it { is_expected.to compile.with_all_deps } it 'has server.key file' do is_expected.to contain_file('postgres private key') .with( ensure: 'present', owner: 'postgres', mode: '0600', path: "#{datadir_path}/server.key", ) .that_requires('Package[postgresql-server]') end it 'has server.crt file' do is_expected.to contain_file('postgres public key') .with( ensure: 'present', owner: 'postgres', mode: '0600', path: "#{datadir_path}/server.crt", ) .that_requires('Package[postgresql-server]') end it 'has ssl config attribute' do is_expected.to contain_postgresql__server__config_entry('ssl') .with_value('on').with_ensure('present') .that_requires('File[postgres private key]') .that_requires('File[postgres public key]') end it 'has ssl_cert_file config attribute' do is_expected.to contain_postgresql__server__config_entry('ssl_cert_file') .with_value("#{datadir_path}/server.crt").with_ensure('present') .that_requires('File[postgres private key]') .that_requires('File[postgres public key]') end it 'has ssl_key_file config attribute' do is_expected.to contain_postgresql__server__config_entry('ssl_key_file') .with_value("#{datadir_path}/server.key").with_ensure('present') .that_requires('File[postgres private key]') .that_requires('File[postgres public key]') end it 'has ssl_ca_file config attribute' do is_expected.to contain_postgresql__server__config_entry('ssl_ca_file') .with_value(params[:postgresql_ssl_ca_cert_path]).with_ensure('present') .that_requires('File[postgres private key]') .that_requires('File[postgres public key]') end - it 'has hba rule for ipv4' do + it 'has hba rule for puppetdb user ipv4' do is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:database_username]} (ipv4)") .with_type('hostssl') .with_database(params[:database_name]) .with_user(params[:database_username]) .with_address('0.0.0.0/0') .with_auth_method('cert') .with_order(0) .with_auth_option("map=#{identity_map} clientcert=1") end - it 'has hba rule for ipv6' do + it 'does not create hba rule for puppetdb-read user ipv4' do + is_expected.not_to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:read_database_username]} (ipv4)") + end + + it 'has hba rule for puppetdb user ipv6' do is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:database_username]} (ipv6)") .with_type('hostssl') .with_database(params[:database_name]) .with_user(params[:database_username]) .with_address('::0/0') .with_auth_method('cert') .with_order(0) .with_auth_option("map=#{identity_map} clientcert=1") end + it 'does not create hba rule for puppetdb-read user ipv6' do + is_expected.not_to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:read_database_username]} (ipv6)") + end + it 'has ident rule' do is_expected.to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{params[:database_username]} user") .with_map_name(identity_map) .with_system_username(facts[:fqdn]) .with_database_username(params[:database_name]) end + it 'does not create read ident rule' do + is_expected.not_to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{params[:read_database_username]} user") + end + context 'when the puppetdb_server is set' do let(:params) do { puppetdb_server: 'puppetdb_fqdn', database_name: 'puppetdb', database_username: 'puppetdb', } end it 'has ident rule with the specified puppetdb_server host' do is_expected.to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{params[:database_username]} user") .with_map_name(identity_map) .with_system_username(params[:puppetdb_server]) .with_database_username(params[:database_name]) end end + + context 'when the create_read_user_rule is set to true' do + let(:params) do + { + database_name: 'puppetdb', + read_database_username: 'puppetdb-read', + create_read_user_rule: true, + } + end + + it 'has hba rule for puppetdb-read user ipv4' do + is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:read_database_username]} (ipv4)") + .with_type('hostssl') + .with_database(params[:database_name]) + .with_user(params[:read_database_username]) + .with_address('0.0.0.0/0') + .with_auth_method('cert') + .with_order(0) + .with_auth_option("map=#{read_identity_map} clientcert=1") + end + + it 'has hba rule for puppetdb-read user ipv6' do + is_expected.to contain_postgresql__server__pg_hba_rule("Allow certificate mapped connections to #{params[:database_name]} as #{params[:read_database_username]} (ipv6)") + .with_type('hostssl') + .with_database(params[:database_name]) + .with_user(params[:read_database_username]) + .with_address('::0/0') + .with_auth_method('cert') + .with_order(0) + .with_auth_option("map=#{read_identity_map} clientcert=1") + end + + it 'has read ident rule' do + is_expected.to contain_postgresql__server__pg_ident_rule("Map the SSL certificate of the server as a #{params[:read_database_username]} user") + .with_map_name(read_identity_map) + .with_system_username(facts[:fqdn]) + .with_database_username(params[:read_database_username]) + end + end end end diff --git a/spec/unit/classes/server/db_read_uri_spec.rb b/spec/unit/classes/server/db_read_uri_spec.rb index a273ff9..b7943e1 100644 --- a/spec/unit/classes/server/db_read_uri_spec.rb +++ b/spec/unit/classes/server/db_read_uri_spec.rb @@ -1,73 +1,73 @@ require 'spec_helper' describe 'puppetdb::server::read_database', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', operatingsystemrelease: '7.0', fqdn: 'test.domain.local', } end describe 'when passing jdbc subparams' do let(:params) do { - database_host: 'localhost', + read_database_host: 'localhost', jdbc_ssl_properties: '?ssl=true', } end it { is_expected.to contain_ini_setting('puppetdb_read_subname') .with( section: 'read-database', setting: 'subname', value: '//localhost:5432/puppetdb?ssl=true', ) } end describe 'when using ssl communication' do let(:params) do { - database_host: 'cheery-rime.puppetlabs.net', + read_database_host: 'cheery-rime.puppetlabs.net', postgresql_ssl_on: true, ssl_key_pk8_path: '/tmp/private_key.pk8', } end it 'configures subname correctly' do is_expected.to contain_ini_setting('puppetdb_read_subname') .with( ensure: 'present', path: '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', section: 'read-database', setting: 'subname', value: '//cheery-rime.puppetlabs.net:5432/puppetdb?' \ 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ 'sslmode=verify-full&' \ 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ 'sslkey=/tmp/private_key.pk8&' \ 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', ) end context 'when setting jdbc_ssl_properties as well' do let(:params) do { - database_host: 'puppetdb', + read_database_host: 'puppetdb', jdbc_ssl_properties: '?ssl=true', postgresql_ssl_on: true, } end it 'raises an error' do is_expected.to compile .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) end end end end end diff --git a/spec/unit/classes/server/read_database_ini_spec.rb b/spec/unit/classes/server/read_database_ini_spec.rb index bfae492..502cdbc 100644 --- a/spec/unit/classes/server/read_database_ini_spec.rb +++ b/spec/unit/classes/server/read_database_ini_spec.rb @@ -1,170 +1,170 @@ require 'spec_helper' describe 'puppetdb::server::read_database', type: :class do context 'on a supported platform' do let(:facts) do { osfamily: 'RedHat', operatingsystem: 'RedHat', puppetversion: Puppet.version, operatingsystemrelease: '7.0', fqdn: 'test.domain.local', } end it { is_expected.to contain_class('puppetdb::server::read_database') } describe 'when using default values' do it { is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/read_database.ini').with('ensure' => 'absent') } end describe 'when using minimum working values' do let(:params) do { - 'database_host' => 'puppetdb', + 'read_database_host' => 'puppetdb', } end it { is_expected.to contain_file('/etc/puppetlabs/puppetdb/conf.d/read_database.ini') .with( 'ensure' => 'file', 'owner' => 'puppetdb', 'group' => 'puppetdb', 'mode' => '0600', ) } it { is_expected.to contain_ini_setting('puppetdb_read_database_username') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'username', - 'value' => 'puppetdb', + 'value' => 'puppetdb-read', ) } it { is_expected.to contain_ini_setting('puppetdb_read_database_password') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'password', - 'value' => 'puppetdb', + 'value' => 'puppetdb-read', ) } it { is_expected.to contain_ini_setting('puppetdb_read_classname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'classname', 'value' => 'org.postgresql.Driver', ) } it { is_expected.to contain_ini_setting('puppetdb_read_subprotocol') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'subprotocol', 'value' => 'postgresql', ) } it { is_expected.to contain_ini_setting('puppetdb_read_subname') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'subname', 'value' => '//puppetdb:5432/puppetdb', ) } it { is_expected.to contain_ini_setting('puppetdb_read_log_slow_statements') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'log-slow-statements', 'value' => 10, ) } it { is_expected.to contain_ini_setting('puppetdb_read_conn_max_age') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'conn-max-age', 'value' => '60', ) } it { is_expected.to contain_ini_setting('puppetdb_read_conn_keep_alive') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'conn-keep-alive', 'value' => '45', ) } it { is_expected.to contain_ini_setting('puppetdb_read_conn_lifetime') .with( 'ensure' => 'present', 'path' => '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', 'section' => 'read-database', 'setting' => 'conn-lifetime', 'value' => '0', ) } context 'when using ssl communication' do let(:params) do { - database_host: 'puppetdb', + read_database_host: 'puppetdb', postgresql_ssl_on: true, ssl_key_pk8_path: '/tmp/private_key.pk8', } end it 'configures subname correctly' do is_expected.to contain_ini_setting('puppetdb_read_subname') .with( ensure: 'present', path: '/etc/puppetlabs/puppetdb/conf.d/read_database.ini', section: 'read-database', setting: 'subname', value: '//puppetdb:5432/puppetdb?' \ 'ssl=true&sslfactory=org.postgresql.ssl.LibPQFactory&' \ 'sslmode=verify-full&' \ 'sslrootcert=/etc/puppetlabs/puppetdb/ssl/ca.pem&' \ 'sslkey=/tmp/private_key.pk8&' \ 'sslcert=/etc/puppetlabs/puppetdb/ssl/public.pem', ) end context 'when setting jdbc_ssl_properties as well' do let(:params) do { - database_host: 'puppetdb', + read_database_host: 'puppetdb', jdbc_ssl_properties: '?ssl=true', postgresql_ssl_on: true, } end it 'raises an error' do is_expected.to compile .and_raise_error(%r{Variables 'postgresql_ssl_on' and 'jdbc_ssl_properties' can not be used at the same time!}) end end end end end end