From 06dbd089747f2480cd1e6cf7b64013db2597643e Mon Sep 17 00:00:00 2001 From: Alvar Penning Date: Fri, 13 Feb 2026 16:50:17 +0100 Subject: [PATCH] Introduce Password File Configuration A new password_file YAML key or PASSWORD_FILE environment variable is introduced next to password in configurations. When used, it takes precedence over password, but populates the password from the given file. Having passwords in a separate file from the main configuration might be desired when using a configuration management software together with a secret manager, e.g., Ansible together with SOPS. Another use case are containers, configured through environment variables, where one might not want to directly put a password. This is possible through an update to the IGL: https://github.com/Icinga/icinga-go-library/pull/180 --- config.example.yml | 3 ++ doc/03-Configuration.md | 68 +++++++++++++++++++++------------------ go.mod | 7 ++-- go.sum | 17 +++++++--- internal/config/config.go | 11 ++++--- 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/config.example.yml b/config.example.yml index 0112e00f..8a61b74d 100644 --- a/config.example.yml +++ b/config.example.yml @@ -22,6 +22,7 @@ database: # Database password. password: CHANGEME +# password_file: /run/secerets/icingadb_database_password # List of low-level database options that can be set to influence some Icinga DB internal default behaviours. # Do not change the defaults if you don't have to! @@ -74,6 +75,7 @@ redis: # Authentication password. May be used alone or together with a `username`. # password: +# password_file: /run/secerets/icingadb_redis_password # Numerical database identifier, defaults to `0`. # database: 0 @@ -151,3 +153,4 @@ redis: # Password for the defined user. # password: insecureinsecure +# password_file: /run/secerets/icingadb_notifications_password diff --git a/doc/03-Configuration.md b/doc/03-Configuration.md index f7502e3c..8875039e 100644 --- a/doc/03-Configuration.md +++ b/doc/03-Configuration.md @@ -12,6 +12,9 @@ When using environment variables, the variable name is constructed by concatenat The hyphens in the names are to be replaced by underscores. For example, to set the database host, the `ICINGADB_DATABASE_HOST` environment variable is used. +Passwords can be set directly or stored in a separate file, referenced via the `password_file` YAML key or `PASSWORD_FILE` environment variable. +Only one of these two options can be used. + ## Database Configuration Connection configuration for the SQL database to which Icinga DB synchronizes monitoring data. @@ -23,20 +26,21 @@ In [high availability setups](05-Distributed-Setups.md), all Icinga DB instances For YAML configuration, the options are part of the `database` dictionary. For environment variables, each option is prefixed with`ICINGADB_DATABASE_`. -| Option | Description | -|----------|------------------------------------------------------------------------------------------------------------------------------------------------| -| type | **Optional.** Either `mysql` (default) or `pgsql`. | -| host | **Required.** Database host or absolute Unix socket path. | -| port | **Optional.** Database port. By default, the MySQL or PostgreSQL port, depending on the database type. | -| database | **Required.** Database name. | -| user | **Required.** Database username. | -| password | **Optional.** Database password. | -| tls | **Optional.** Whether to use TLS. | -| cert | **Optional.** TLS client certificate, either file path or PEM-encoded multiline string. | -| key | **Optional.** TLS client private key, either file path or PEM-encoded multiline string. | -| ca | **Optional.** TLS CA certificate, either file path or PEM-encoded multiline string. | -| insecure | **Optional.** Whether not to verify the peer. | -| options | **Optional.** List of low-level [database options](#database-options) that can be set to influence some Icinga DB internal default behaviours. | +| Option | Description | +|---------------|------------------------------------------------------------------------------------------------------------------------------------------------| +| type | **Optional.** Either `mysql` (default) or `pgsql`. | +| host | **Required.** Database host or absolute Unix socket path. | +| port | **Optional.** Database port. By default, the MySQL or PostgreSQL port, depending on the database type. | +| database | **Required.** Database name. | +| user | **Required.** Database username. | +| password | **Optional.** Database password. | +| password_file | **Optional.** Database password file. | +| tls | **Optional.** Whether to use TLS. | +| cert | **Optional.** TLS client certificate, either file path or PEM-encoded multiline string. | +| key | **Optional.** TLS client private key, either file path or PEM-encoded multiline string. | +| ca | **Optional.** TLS CA certificate, either file path or PEM-encoded multiline string. | +| insecure | **Optional.** Whether not to verify the peer. | +| options | **Optional.** List of low-level [database options](#database-options) that can be set to influence some Icinga DB internal default behaviours. | ### Database Options @@ -72,18 +76,19 @@ High availability setups require a dedicated Redis® server per Icinga 2 node an For YAML configuration, the options are part of the `redis` dictionary. For environment variables, each option is prefixed with `ICINGADB_REDIS_`. -| Option | Description | -|----------|-------------------------------------------------------------------------------------------------------------------------| -| host | **Required.** Host name or address, or absolute Unix socket path. | -| port | **Optional.** TCP port. Defaults to `6380` matching the Redis® open source server port in the `icingadb-redis` package. | -| username | **Optional.** Authentication username, requires a `password` being set as well. | -| password | **Optional.** Authentication password. May be used alone or together with a `username`. | -| database | **Optional.** Numerical database identifier, defaults to `0`. | -| tls | **Optional.** Whether to use TLS. | -| cert | **Optional.** TLS client certificate, either file path or PEM-encoded multiline string. | -| key | **Optional.** TLS client private key, either file path or PEM-encoded multiline string. | -| ca | **Optional.** TLS CA certificate, either file path or PEM-encoded multiline string. | -| insecure | **Optional.** Whether not to verify the peer. | +| Option | Description | +|---------------|-------------------------------------------------------------------------------------------------------------------------| +| host | **Required.** Host name or address, or absolute Unix socket path. | +| port | **Optional.** TCP port. Defaults to `6380` matching the Redis® open source server port in the `icingadb-redis` package. | +| username | **Optional.** Authentication username, requires a `password` being set as well. | +| password | **Optional.** Authentication password. May be used alone or together with a `username`. | +| password_file | **Optional.** Authentication password file. | +| database | **Optional.** Numerical database identifier, defaults to `0`. | +| tls | **Optional.** Whether to use TLS. | +| cert | **Optional.** TLS client certificate, either file path or PEM-encoded multiline string. | +| key | **Optional.** TLS client private key, either file path or PEM-encoded multiline string. | +| ca | **Optional.** TLS CA certificate, either file path or PEM-encoded multiline string. | +| insecure | **Optional.** Whether not to verify the peer. | ## Logging Configuration @@ -196,11 +201,12 @@ If configured, Icinga DB will submit events to the Icinga Notifications API. For YAML configuration, the options are part of the `notifications` dictionary. For environment variables, each option is prefixed with `ICINGADB_NOTIFICATIONS_`. -| Option | Description | -|----------|-----------------------------------------------------------------------------------| -| url | **Optional.** Icinga Notifications API base URL, such as `http://localhost:5680`. | -| username | **Optional.** Icinga Notifications API user for this source. | -| password | **Optional.** Icinga Notifications API user password. | +| Option | Description | +|---------------|-----------------------------------------------------------------------------------| +| url | **Optional.** Icinga Notifications API base URL, such as `http://localhost:5680`. | +| username | **Optional.** Icinga Notifications API user for this source. | +| password | **Optional.** Icinga Notifications API user password. | +| password_file | **Optional.** Icinga Notifications API user password file. | ## Appendix diff --git a/go.mod b/go.mod index a22084ea..e2fa30c1 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/goccy/go-yaml v1.13.0 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 - github.com/icinga/icinga-go-library v0.8.2 + github.com/icinga/icinga-go-library v0.8.3-0.20260219142441-bea1975cae65 github.com/jessevdk/go-flags v1.6.1 github.com/jmoiron/sqlx v1.4.0 github.com/mattn/go-sqlite3 v1.14.34 @@ -29,14 +29,15 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.18.0 // indirect github.com/go-sql-driver/mysql v1.9.3 // indirect - github.com/lib/pq v1.10.9 // indirect + github.com/lib/pq v1.11.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/redis/go-redis/v9 v9.17.2 // indirect + github.com/redis/go-redis/v9 v9.18.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/ssgreg/journald v1.0.0 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/sys v0.26.0 // indirect diff --git a/go.sum b/go.sum index e8e646c1..607782ff 100644 --- a/go.sum +++ b/go.sum @@ -38,16 +38,19 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/icinga/icinga-go-library v0.8.2 h1:/TwrRotn0QZl/2Vo1jCUaZs1isH5uve9lTnkRYTIHnI= -github.com/icinga/icinga-go-library v0.8.2/go.mod h1:9SwyGO3NV3nXI8TzKoIrlK8SG+1arK1jm9MDYAW6N7M= +github.com/icinga/icinga-go-library v0.8.3-0.20260219142441-bea1975cae65 h1:hVSc31fdr6zwqC5+c2luNhv32NSfRhtqlAgTv0+Xl/0= +github.com/icinga/icinga-go-library v0.8.3-0.20260219142441-bea1975cae65/go.mod h1:yccAMrqQc1n3lCt/Ic8gmHaSdDyNyhnameqR30n2Nb4= github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs= +github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -64,8 +67,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI= -github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= +github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs= +github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -75,6 +78,10 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/vbauerster/mpb/v6 v6.0.4 h1:h6J5zM/2wimP5Hj00unQuV8qbo5EPcj6wbkCqgj7KcY= github.com/vbauerster/mpb/v6 v6.0.4/go.mod h1:a/+JT57gqh6Du0Ay5jSR+uBMfXGdlR7VQlGP52fJxLM= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= diff --git a/internal/config/config.go b/internal/config/config.go index 71559f3c..51d3be9a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -35,16 +35,19 @@ func (c *Config) SetDefaults() { // Validate checks constraints in the supplied configuration and returns an error if they are violated. func (c *Config) Validate() error { if err := c.Database.Validate(); err != nil { - return err + return errors.Wrap(err, "invalid database configuration") } if err := c.Redis.Validate(); err != nil { - return err + return errors.Wrap(err, "invalid redis configuration") } if err := c.Logging.Validate(); err != nil { - return err + return errors.Wrap(err, "invalid logging configuration") } if err := c.Retention.Validate(); err != nil { - return err + return errors.Wrap(err, "invalid retention configuration") + } + if err := c.Notifications.Validate(); err != nil { + return errors.Wrap(err, "invalid notifications configuration") } return nil