diff --git a/README.md b/README.md index cc9df968..5d50bc0e 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,42 @@ vault::storage: - leader_api_addr: https://vault3:8200 ``` +## Vault Agent Configuration + +When running Vault in agent mode (`mode => 'agent'`), you can configure the agent behavior using these parameters: + +```puppet +class { 'vault': + mode => 'agent', + agent_vault => { + 'address' => 'https://vault.example.com:8200' + }, + agent_auto_auth => { + 'method' => [{ + 'type' => 'approle', + 'mount_path' => 'auth/approle', + 'config' => { + 'role_id_file_path' => '/etc/vault/role-id', + 'secret_id_file_path' => '/etc/vault/secret-id' + } + } + }], + agent_cache => { + 'use_auto_auth_token' => true + }, + agent_listeners => [{ + 'tcp' => { + 'address' => '127.0.0.1:8100', + 'tls_disable' => true + } + }], + agent_template => { + 'source' => '/etc/vault/template.ctmpl', + 'destination' => '/etc/myapp/config.yml' + } +} +``` + ## mlock By default vault will use the `mlock` system call, therefore the executable will need the corresponding capability. @@ -205,4 +241,4 @@ This module was forked from https://github.com/jsok/puppet-vault ## Related Projects * [hiera-vault](https://github.com/petems/petems-hiera_vault): A Hiera storage backend to retrieve secrets from Hashicorp's Vault - * [vault_lookup](https://github.com/voxpupuli/puppet-vault_lookup): A puppet (deferred) function to do lookups in Vault + * [vault_lookup](https://github.com/voxpupuli/puppet-vault_lookup): A puppet (deferred) function to do lookups in Vault \ No newline at end of file diff --git a/REFERENCE.md b/REFERENCE.md index 8a8368c2..c27d1798 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -21,7 +21,7 @@ ### `vault` -install hashicorp vault +Agent specific parameters #### Parameters @@ -46,6 +46,7 @@ The following parameters are available in the `vault` class: * [`num_procs`](#-vault--num_procs) * [`api_addr`](#-vault--api_addr) * [`version`](#-vault--version) +* [`mode`](#-vault--mode) * [`extra_config`](#-vault--extra_config) * [`enable_ui`](#-vault--enable_ui) * [`arch`](#-vault--arch) @@ -72,6 +73,16 @@ The following parameters are available in the `vault` class: * [`manage_config_file`](#-vault--manage_config_file) * [`download_filename`](#-vault--download_filename) * [`manage_config_dir`](#-vault--manage_config_dir) +* [`agent_vault`](#-vault--agent_vault) +* [`agent_auto_auth`](#-vault--agent_auto_auth) +* [`agent_api_proxy`](#-vault--agent_api_proxy) +* [`agent_cache`](#-vault--agent_cache) +* [`agent_listeners`](#-vault--agent_listeners) +* [`agent_template`](#-vault--agent_template) +* [`agent_template_config`](#-vault--agent_template_config) +* [`agent_exec`](#-vault--agent_exec) +* [`agent_env_template`](#-vault--agent_env_template) +* [`agent_telemetry`](#-vault--agent_telemetry) ##### `user` @@ -234,11 +245,19 @@ The version of Vault to install Default value: `'1.12.0'` +##### `mode` + +Data type: `Enum['server', 'agent']` + +Whether to start vault in 'server' or 'agent' mode + +Default value: `'server'` + ##### `extra_config` Data type: `Hash` - +Hash containing extra configuration options to merge with the generated config Default value: `{}` @@ -246,7 +265,7 @@ Default value: `{}` Data type: `Optional[Boolean]` - +Whether to enable the Vault web UI Default value: `undef` @@ -254,7 +273,7 @@ Default value: `undef` Data type: `Any` - +System architecture for the Vault binary (automatically determined) Default value: `$vault::params::arch` @@ -262,7 +281,7 @@ Default value: `$vault::params::arch` Data type: `Any` - +Operating system for the Vault binary (automatically determined) Default value: `downcase($facts['kernel'])` @@ -270,7 +289,7 @@ Default value: `downcase($facts['kernel'])` Data type: `Any` - +Whether to manage the download directory Default value: `false` @@ -278,7 +297,7 @@ Default value: `false` Data type: `Any` - +Directory where the Vault archive will be downloaded Default value: `'/tmp'` @@ -286,7 +305,7 @@ Default value: `'/tmp'` Data type: `Any` - +The state the package should be in (installed, absent, latest) Default value: `'installed'` @@ -294,7 +313,7 @@ Default value: `'installed'` Data type: `Any` - +Name of the Vault package Default value: `'vault'` @@ -302,7 +321,7 @@ Default value: `'vault'` Data type: `Any` - +Installation method: 'archive' or 'repo' Default value: `$vault::params::install_method` @@ -310,7 +329,7 @@ Default value: `$vault::params::install_method` Data type: `Any` - +Whether to manage Linux file capabilities for vault binary Default value: `undef` @@ -318,7 +337,7 @@ Default value: `undef` Data type: `Any` - +Whether to disable the memory lock capability Default value: `undef` @@ -326,7 +345,7 @@ Default value: `undef` Data type: `Optional[String]` - +Specifies the maximum possible lease duration for tokens and secrets Default value: `undef` @@ -334,7 +353,7 @@ Default value: `undef` Data type: `Optional[String]` - +Specifies the default lease duration for tokens and secrets Default value: `undef` @@ -342,7 +361,7 @@ Default value: `undef` Data type: `Optional[Hash]` - +Hash containing Vault telemetry configuration Default value: `undef` @@ -350,7 +369,7 @@ Default value: `undef` Data type: `Optional[Boolean]` - +Disable caching Default value: `undef` @@ -358,7 +377,7 @@ Default value: `undef` Data type: `Optional[Hash]` - +Hash containing seal configuration options Default value: `undef` @@ -366,7 +385,7 @@ Default value: `undef` Data type: `Optional[Hash]` - +Hash containing storage configuration for HA setup Default value: `undef` @@ -374,7 +393,7 @@ Default value: `undef` Data type: `Variant[Hash, Array[Hash]]` - +Hash or Array of hashes containing listener configuration Default value: `{ 'tcp' => { 'address' => '127.0.0.1:8200', 'tls_disable' => 1 }, }` @@ -382,7 +401,7 @@ Default value: `{ 'tcp' => { 'address' => '127.0.0.1:8200', 'tls_disable' => 1 } Data type: `Any` - +Whether to manage the storage directory Default value: `false` @@ -390,7 +409,7 @@ Default value: `false` Data type: `Hash` - +Hash containing storage configuration Default value: `{ 'file' => { 'path' => '/var/lib/vault' } }` @@ -398,7 +417,7 @@ Default value: `{ 'file' => { 'path' => '/var/lib/vault' } }` Data type: `Optional[Boolean]` - +Whether to manage the service file Default value: `$vault::params::manage_service_file` @@ -406,7 +425,7 @@ Default value: `$vault::params::manage_service_file` Data type: `Any` - +Desired state of the Vault service (running, stopped) Default value: `'running'` @@ -414,7 +433,7 @@ Default value: `'running'` Data type: `Any` - +Whether to enable the Vault service on boot Default value: `true` @@ -422,7 +441,7 @@ Default value: `true` Data type: `Any` - +Whether to manage the Vault config file Default value: `true` @@ -430,7 +449,7 @@ Default value: `true` Data type: `Any` - +Filename for the downloaded archive Default value: `'vault.zip'` @@ -438,7 +457,87 @@ Default value: `'vault.zip'` Data type: `Boolean` -enable/disable the directory management. not required for package based installations +Whether to manage the configuration directory Default value: `$install_method == 'archive'` +##### `agent_vault` + +Data type: `Optional[Hash]` + +Hash containing Vault server connection configuration for agent mode + +Default value: `undef` + +##### `agent_auto_auth` + +Data type: `Optional[Hash]` + +Hash containing auto-auth configuration for agent mode + +Default value: `undef` + +##### `agent_api_proxy` + +Data type: `Optional[Hash]` + +Hash containing API proxy configuration for agent mode + +Default value: `undef` + +##### `agent_cache` + +Data type: `Optional[Hash]` + +Hash containing cache configuration for agent mode + +Default value: `undef` + +##### `agent_listeners` + +Data type: `Optional[Array[Hash]]` + +Array of hashes containing listener configuration for agent mode + +Default value: `undef` + +##### `agent_template` + +Data type: `Optional[Hash]` + +Hash containing template configuration for agent mode + +Default value: `undef` + +##### `agent_template_config` + +Data type: `Optional[Hash]` + +Hash containing template engine configuration for agent mode + +Default value: `undef` + +##### `agent_exec` + +Data type: `Optional[Hash]` + +Hash containing exec configuration for agent mode + +Default value: `undef` + +##### `agent_env_template` + +Data type: `Optional[Hash]` + +Hash containing environment template configuration for agent mode + +Default value: `undef` + +##### `agent_telemetry` + +Data type: `Optional[Hash]` + +Hash containing telemetry configuration for agent mode + +Default value: `undef` + diff --git a/manifests/config.pp b/manifests/config.pp index 01586318..19688e6a 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -16,19 +16,40 @@ } if $vault::manage_config_file { - $_config_hash = delete_undef_values({ - 'listener' => $vault::listener, - 'storage' => $vault::storage, - 'ha_storage' => $vault::ha_storage, - 'seal' => $vault::seal, - 'telemetry' => $vault::telemetry, - 'disable_cache' => $vault::disable_cache, - 'default_lease_ttl' => $vault::default_lease_ttl, - 'max_lease_ttl' => $vault::max_lease_ttl, - 'disable_mlock' => $vault::disable_mlock, - 'ui' => $vault::enable_ui, - 'api_addr' => $vault::api_addr, - }) + case $vault::mode { + 'server': { + $_config_hash = delete_undef_values({ + 'listener' => $vault::listener, + 'storage' => $vault::storage, + 'ha_storage' => $vault::ha_storage, + 'seal' => $vault::seal, + 'telemetry' => $vault::telemetry, + 'disable_cache' => $vault::disable_cache, + 'default_lease_ttl' => $vault::default_lease_ttl, + 'max_lease_ttl' => $vault::max_lease_ttl, + 'disable_mlock' => $vault::disable_mlock, + 'ui' => $vault::enable_ui, + 'api_addr' => $vault::api_addr, + }) + } + 'agent': { + $_config_hash = delete_undef_values({ + 'vault' => $vault::agent_vault, + 'auto_auth' => $vault::agent_auto_auth, + 'api_proxy' => $vault::agent_api_proxy, + 'cache' => $vault::agent_cache, + 'listener' => $vault::agent_listeners, + 'template' => $vault::agent_template, + 'template_config' => $vault::agent_template_config, + 'exec' => $vault::agent_exec, + 'env_template' => $vault::agent_env_template, + 'telemetry' => $vault::agent_telemetry, + }) + } + default: { + fail("Unsupported vault mode: ${vault::mode}") + } + } $config_hash = merge($_config_hash, $vault::extra_config) diff --git a/manifests/init.pp b/manifests/init.pp index da997dee..3ccaaa3c 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -50,78 +50,103 @@ # # @param version The version of Vault to install # -# @param extra_config -# @param enable_ui -# @param arch -# @param os -# @param manage_download_dir -# @param download_dir -# @param package_ensure -# @param package_name -# @param install_method -# @param manage_file_capabilities -# @param disable_mlock -# @param max_lease_ttl -# @param default_lease_ttl -# @param telemetry -# @param disable_cache -# @param seal -# @param ha_storage -# @param listener -# @param manage_storage_dir -# @param storage -# @param manage_service_file -# @param service_ensure -# @param service_enable -# @param manage_config_file -# @param download_filename -# @param manage_config_dir enable/disable the directory management. not required for package based installations +# @param mode Whether to start vault in 'server' or 'agent' mode +# @param extra_config Hash containing extra configuration options to merge with the generated config +# @param enable_ui Whether to enable the Vault web UI +# @param arch System architecture for the Vault binary (automatically determined) +# @param os Operating system for the Vault binary (automatically determined) +# @param manage_download_dir Whether to manage the download directory +# @param download_dir Directory where the Vault archive will be downloaded +# @param package_ensure The state the package should be in (installed, absent, latest) +# @param package_name Name of the Vault package +# @param install_method Installation method: 'archive' or 'repo' +# @param manage_file_capabilities Whether to manage Linux file capabilities for vault binary +# @param disable_mlock Whether to disable the memory lock capability +# @param max_lease_ttl Specifies the maximum possible lease duration for tokens and secrets +# @param default_lease_ttl Specifies the default lease duration for tokens and secrets +# @param telemetry Hash containing Vault telemetry configuration +# @param disable_cache Disable caching +# @param seal Hash containing seal configuration options +# @param ha_storage Hash containing storage configuration for HA setup +# @param listener Hash or Array of hashes containing listener configuration +# @param manage_storage_dir Whether to manage the storage directory +# @param storage Hash containing storage configuration +# @param manage_service_file Whether to manage the service file +# @param service_ensure Desired state of the Vault service (running, stopped) +# @param service_enable Whether to enable the Vault service on boot +# @param manage_config_file Whether to manage the Vault config file +# @param download_filename Filename for the downloaded archive +# @param manage_config_dir Whether to manage the configuration directory +# +# Agent specific parameters +# @param agent_vault Hash containing Vault server connection configuration for agent mode +# @param agent_auto_auth Hash containing auto-auth configuration for agent mode +# @param agent_api_proxy Hash containing API proxy configuration for agent mode +# @param agent_cache Hash containing cache configuration for agent mode +# @param agent_listeners Array of hashes containing listener configuration for agent mode +# @param agent_template Hash containing template configuration for agent mode +# @param agent_template_config Hash containing template engine configuration for agent mode +# @param agent_exec Hash containing exec configuration for agent mode +# @param agent_env_template Hash containing environment template configuration for agent mode +# @param agent_telemetry Hash containing telemetry configuration for agent mode class vault ( - $user = 'vault', - $manage_user = true, - $group = 'vault', - $manage_group = true, - $bin_dir = $vault::params::bin_dir, - $manage_config_file = true, - $config_mode = '0750', - $purge_config_dir = true, - $download_url = undef, - $download_url_base = 'https://releases.hashicorp.com/vault/', - $download_extension = 'zip', - $service_name = 'vault', - $service_enable = true, - $service_ensure = 'running', - $service_provider = $facts['service_provider'], - Boolean $manage_repo = $vault::params::manage_repo, - $manage_service = true, + $user = 'vault', + $manage_user = true, + $group = 'vault', + $manage_group = true, + $bin_dir = $vault::params::bin_dir, + $manage_config_file = true, + Enum['server', 'agent'] $mode = 'server', + $config_mode = '0750', + $purge_config_dir = true, + $download_url = undef, + $download_url_base = 'https://releases.hashicorp.com/vault/', + $download_extension = 'zip', + $service_name = 'vault', + $service_enable = true, + $service_ensure = 'running', + $service_provider = $facts['service_provider'], + Boolean $manage_repo = $vault::params::manage_repo, + $manage_service = true, Optional[Boolean] $manage_service_file = $vault::params::manage_service_file, - Hash $storage = { 'file' => { 'path' => '/var/lib/vault' } }, - $manage_storage_dir = false, - Variant[Hash, Array[Hash]] $listener = { 'tcp' => { 'address' => '127.0.0.1:8200', 'tls_disable' => 1 }, }, - Optional[Hash] $ha_storage = undef, - Optional[Hash] $seal = undef, - Optional[Boolean] $disable_cache = undef, - Optional[Hash] $telemetry = undef, - Optional[String] $default_lease_ttl = undef, - Optional[String] $max_lease_ttl = undef, - $disable_mlock = undef, - $manage_file_capabilities = undef, - $service_options = '', - $num_procs = $facts['processors']['count'], - $install_method = $vault::params::install_method, - $config_dir = if $install_method == 'repo' and $manage_repo { '/etc/vault.d' } else { '/etc/vault' }, - $package_name = 'vault', - $package_ensure = 'installed', - $download_dir = '/tmp', - $manage_download_dir = false, - $download_filename = 'vault.zip', - $version = '1.12.0', - $os = downcase($facts['kernel']), - $arch = $vault::params::arch, - Optional[Boolean] $enable_ui = undef, - Optional[String] $api_addr = undef, - Hash $extra_config = {}, - Boolean $manage_config_dir = $install_method == 'archive', + Hash $storage = { 'file' => { 'path' => '/var/lib/vault' } }, + $manage_storage_dir = false, + Variant[Hash, Array[Hash]] $listener = { 'tcp' => { 'address' => '127.0.0.1:8200', 'tls_disable' => 1 }, }, + Optional[Hash] $ha_storage = undef, + Optional[Hash] $seal = undef, + Optional[Boolean] $disable_cache = undef, + Optional[Hash] $telemetry = undef, + Optional[String] $default_lease_ttl = undef, + Optional[String] $max_lease_ttl = undef, + $disable_mlock = undef, + $manage_file_capabilities = undef, + $service_options = '', + $num_procs = $facts['processors']['count'], + $install_method = $vault::params::install_method, + $config_dir = if $install_method == 'repo' and $manage_repo { '/etc/vault.d' } else { '/etc/vault' }, + $package_name = 'vault', + $package_ensure = 'installed', + $download_dir = '/tmp', + $manage_download_dir = false, + $download_filename = 'vault.zip', + $version = '1.12.0', + $os = downcase($facts['kernel']), + $arch = $vault::params::arch, + Optional[Boolean] $enable_ui = undef, + Optional[String] $api_addr = undef, + Hash $extra_config = {}, + Boolean $manage_config_dir = $install_method == 'archive', + # Agent specific parameters + Optional[Hash] $agent_vault = undef, + Optional[Hash] $agent_auto_auth = undef, + Optional[Hash] $agent_api_proxy = undef, + Optional[Hash] $agent_cache = undef, + Optional[Array[Hash]] $agent_listeners = undef, + Optional[Hash] $agent_template = undef, + Optional[Hash] $agent_template_config = undef, + Optional[Hash] $agent_exec = undef, + Optional[Hash] $agent_env_template = undef, + Optional[Hash] $agent_telemetry = undef, ) inherits vault::params { # lint:ignore:140chars $real_download_url = pick($download_url, "${download_url_base}${version}/${package_name}_${version}_${os}_${arch}.${download_extension}") diff --git a/spec/acceptance/class_spec.rb b/spec/acceptance/class_spec.rb index ded93f16..a894f16d 100644 --- a/spec/acceptance/class_spec.rb +++ b/spec/acceptance/class_spec.rb @@ -156,4 +156,46 @@ class { 'vault': it { is_expected.to be_listening.on('127.0.0.1').with('tcp') } end end + + context 'vault class with agent configuration' do + let(:manifest) do + <<-PUPPET + class { 'vault': + mode => 'agent', + agent_vault => { 'address' => 'https://vault.example.com:8200' }, + agent_auto_auth => { + 'method' => [{ + 'type' => 'approle', + 'wrap_ttl' => '1m', + 'config' => { + 'role_id_file_path' => '/etc/vault/role-id', + 'secret_id_file_path' => '/etc/vault/secret-id' + } + }] + }, + agent_cache => { 'use_auto_auth_token' => true }, + agent_listeners => [{ + 'tcp' => { 'address' => '127.0.0.1:8100', 'tls_disable' => true } + }] + } + PUPPET + end + + it 'applies the manifest without error' do + apply_manifest(manifest, catch_failures: true) + end + + it 'creates the config.json with correct settings' do + config_file = file('/etc/vault/config.json') + expect(config_file).to be_file + expect(config_file.content).to include( + '"address": "https://vault.example.com:8200"', + '"wrap_ttl": "1m"', + '"role_id_file_path": "/etc/vault/role-id"', + '"secret_id_file_path": "/etc/vault/secret-id"', + '"use_auto_auth_token": true', + '"address": "127.0.0.1:8100"' + ) + end + end end diff --git a/spec/classes/vault_spec.rb b/spec/classes/vault_spec.rb index 3b680a7a..1641c5d8 100644 --- a/spec/classes/vault_spec.rb +++ b/spec/classes/vault_spec.rb @@ -417,6 +417,52 @@ } end + context 'vault class with agent configuration' do + let(:params) do + { + mode: 'agent', + agent_vault: { 'address' => 'https://vault.example.com:8200' }, + agent_auto_auth: { + 'method' => [{ + 'type' => 'approle', + 'wrap_ttl' => '1m', + 'config' => { + 'role_id_file_path' => '/etc/vault/role-id', + 'secret_id_file_path' => '/etc/vault/secret-id' + } + }] + }, + agent_cache: { 'use_auto_auth_token' => true }, + agent_listeners: [{ + 'tcp' => { + 'address' => '127.0.0.1:8100', + 'tls_disable' => true + } + }] + } + end + + it { is_expected.to compile.with_all_deps } + + it 'generates the config.json with correct agent settings' do + expect(param_value(catalogue, 'File', '/etc/vault/config.json', 'content')).to include_json( + vault: { 'address' => 'https://vault.example.com:8200' }, + auto_auth: { + 'method' => [{ + 'type' => 'approle', + 'wrap_ttl' => '1m', + 'config' => { + 'role_id_file_path' => '/etc/vault/role-id', + 'secret_id_file_path' => '/etc/vault/secret-id' + } + }] + }, + cache: { 'use_auto_auth_token' => true }, + listener: [{ 'tcp' => { 'address' => '127.0.0.1:8100', 'tls_disable' => true } }] + ) + end + end + case os_facts[:os]['family'] when 'RedHat' case os_facts[:os]['release']['major'].to_i @@ -467,6 +513,29 @@ } end + context 'start in agent mode' do + let(:params) do + { mode: 'agent' } + end + + it { + is_expected.to contain_file('/etc/systemd/system/vault.service'). + with_mode('0444'). + with_ensure('file'). + with_owner('root'). + with_group('root'). + with_content(%r{^# vault systemd unit file}). + with_content(%r{^User=vault$}). + with_content(%r{^Group=vault$}). + with_content(%r{Environment=GOMAXPROCS=3}). + with_content(%r{^ExecStart=/usr/local/bin/vault agent -config=/etc/vault/config.json $}). + with_content(%r{SecureBits=keep-caps}). + with_content(%r{Capabilities=CAP_IPC_LOCK\+ep}). + with_content(%r{CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK}). + with_content(%r{NoNewPrivileges=yes}) + } + end + context 'with mlock disabled' do let(:params) do { disable_mlock: true } @@ -641,6 +710,29 @@ } end + context 'start in agent mode' do + let(:params) do + { mode: 'agent' } + end + + it { + is_expected.to contain_file('/etc/systemd/system/vault.service'). + with_mode('0444'). + with_ensure('file'). + with_owner('root'). + with_group('root'). + with_content(%r{^# vault systemd unit file}). + with_content(%r{^User=vault$}). + with_content(%r{^Group=vault$}). + with_content(%r{Environment=GOMAXPROCS=3}). + with_content(%r{^ExecStart=/usr/local/bin/vault agent -config=/etc/vault/config.json $}). + with_content(%r{SecureBits=keep-caps}). + with_content(%r{Capabilities=CAP_IPC_LOCK\+ep}). + with_content(%r{CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK}). + with_content(%r{NoNewPrivileges=yes}) + } + end + context 'with mlock disabled' do let(:params) do { disable_mlock: true } diff --git a/templates/vault.systemd.erb b/templates/vault.systemd.erb index 9cb1d711..26f891d6 100644 --- a/templates/vault.systemd.erb +++ b/templates/vault.systemd.erb @@ -30,7 +30,7 @@ CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK <% end -%> NoNewPrivileges=yes Environment=GOMAXPROCS=<%= scope['vault::num_procs'] %> -ExecStart=<%= scope['vault::bin_dir'] %>/vault server -config=<%= scope['vault::config_dir'] %>/config.json <%= scope['vault::service_options'] %> +ExecStart=<%= scope['vault::bin_dir'] %>/vault <%= scope['vault::mode'] %> -config=<%= scope['vault::config_dir'] %>/config.json <%= scope['vault::service_options'] %> KillSignal=SIGINT TimeoutStopSec=30s Restart=on-failure