From 6d6e7051f3af9abe5b4a8057c696f198852fabfa Mon Sep 17 00:00:00 2001 From: Marcus Young Date: Mon, 24 Apr 2017 09:48:25 -0500 Subject: [PATCH] Add support for tests --- .gitignore | 1 + .kitchen.yml | 94 +++++++++++ .travis.yml | 11 ++ Gemfile | 6 + Gemfile.lock | 149 ++++++++++++++++++ README.md | 0 README.rst | 62 ++++++++ pillar.example | 17 +- test/integration/default/vault_spec.rb | 6 + .../dev_server_systemd/vault_spec.rb | 35 ++++ .../dev_server_upstart/vault_spec.rb | 50 ++++++ .../server_backend_s3/vault_spec.rb | 36 +++++ vault/defaults.yaml | 17 ++ vault/files/server.hcl.jinja | 28 ++-- vault/files/vault_systemd.service.jinja | 10 ++ ...lt.conf.jinja => vault_upstart.conf.jinja} | 5 + vault/init.sls | 28 +++- vault/map.jinja | 16 +- vault/server.sls | 47 +++++- 19 files changed, 568 insertions(+), 50 deletions(-) create mode 100644 .gitignore create mode 100644 .kitchen.yml create mode 100644 .travis.yml create mode 100644 Gemfile create mode 100644 Gemfile.lock delete mode 100644 README.md create mode 100644 README.rst create mode 100644 test/integration/default/vault_spec.rb create mode 100644 test/integration/dev_server_systemd/vault_spec.rb create mode 100644 test/integration/dev_server_upstart/vault_spec.rb create mode 100644 test/integration/server_backend_s3/vault_spec.rb create mode 100644 vault/defaults.yaml create mode 100644 vault/files/vault_systemd.service.jinja rename vault/files/{vault.conf.jinja => vault_upstart.conf.jinja} (78%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7be3c6d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.kitchen diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 0000000..9f8293a --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,94 @@ +--- +driver: + name: docker + use_sudo: false + privileged: true + +verifier: + name: inspec + format: doc + +provisioner: + name: salt_solo + log_level: debug + require_chef: false + formula: vault + +platforms: + - name: ubuntu-16.04 + driver_config: + provision_command: + - locale-gen en_US.UTF-8 + run_command: /sbin/init + privileged: true + pid_one_command: /usr/lib/systemd/systemd + - name: amazonlinux + driver_config: + image: amazonlinux:latest + platform: rhel + run_command: /sbin/init + +suites: + - name: default + provisioner: + state_top: + base: + '*': + - vault + - name: dev_server_systemd + excludes: + - amazonlinux + provisioner: + state_top: + base: + '*': + - vault + - vault.server + pillars: + top.sls: + base: + '*': + - vault + vault.sls: + vault: + service: + type: systemd + - name: dev_server_upstart + includes: + - amazonlinux + provisioner: + state_top: + base: + '*': + - vault + - vault.server + pillars: + top.sls: + base: + '*': + - vault + vault.sls: + vault: + service: + type: upstart + - name: server_backend_s3 + includes: + - amazonlinux + provisioner: + state_top: + base: + '*': + - vault + - vault.server + pillars: + top.sls: + base: + '*': + - vault + vault.sls: + vault: + backend: + type: s3 + bucket: com-saltstack-vault + service: + type: upstart diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3706915 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +sudo: required + +language: ruby + +services: + - docker + +before_install: + - bundle install + +script: bundle exec kitchen verify diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..b4bbecb --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gem "test-kitchen" +gem "kitchen-docker" +gem "kitchen-salt" +gem 'kitchen-inspec' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..d4b5acc --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,149 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.5.1) + public_suffix (~> 2.0, >= 2.0.2) + artifactory (2.8.1) + blankslate (2.1.2.4) + builder (3.2.3) + coderay (1.1.1) + diff-lcs (1.3) + docker-api (1.33.4) + excon (>= 0.38.0) + json + erubis (2.7.0) + excon (0.55.0) + faraday (0.12.1) + multipart-post (>= 1.2, < 3) + ffi (1.9.18) + gssapi (1.2.0) + ffi (>= 1.0.1) + gyoku (1.3.1) + builder (>= 2.1.2) + hashie (3.5.5) + httpclient (2.8.3) + inspec (1.20.0) + addressable (~> 2.4) + faraday (>= 0.9.0) + hashie (~> 3.4) + json (>= 1.8, < 3.0) + method_source (~> 0.8) + mixlib-log + parallel (~> 1.9) + parslet (~> 1.5) + pry (~> 0) + rainbow (~> 2) + rspec (~> 3) + rspec-its (~> 1.2) + rubyzip (~> 1.1) + sslshake (~> 1.1) + thor (~> 0.19) + toml (~> 0.1) + train (>= 0.22.0, < 1.0) + json (2.1.0) + kitchen-docker (2.6.0) + test-kitchen (>= 1.0.0) + kitchen-inspec (0.18.0) + hashie (~> 3.4) + inspec (>= 0.34.0, < 2.0.0) + test-kitchen (~> 1.6) + kitchen-salt (0.0.24) + test-kitchen (~> 1.4) + little-plugger (1.1.4) + logging (2.2.2) + little-plugger (~> 1.1) + multi_json (~> 1.10) + method_source (0.8.2) + mixlib-install (2.1.12) + artifactory + mixlib-shellout + mixlib-versioning + thor + mixlib-log (1.7.1) + mixlib-shellout (2.2.7) + mixlib-versioning (1.1.0) + multi_json (1.12.1) + multipart-post (2.0.0) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (4.1.0) + net-ssh-gateway (1.3.0) + net-ssh (>= 2.6.5) + nori (2.6.0) + parallel (1.11.1) + parslet (1.5.0) + blankslate (~> 2.0) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + public_suffix (2.0.5) + rainbow (2.2.2) + rake + rake (12.0.0) + rspec (3.5.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-core (3.5.4) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-its (1.2.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + rubyntlm (0.6.1) + rubyzip (1.2.1) + safe_yaml (1.0.4) + slop (3.6.0) + sslshake (1.2.0) + test-kitchen (1.16.0) + mixlib-install (>= 1.2, < 3.0) + mixlib-shellout (>= 1.2, < 3.0) + net-scp (~> 1.1) + net-ssh (>= 2.9, < 5.0) + net-ssh-gateway (~> 1.2) + safe_yaml (~> 1.0) + thor (~> 0.19, < 0.19.2) + thor (0.19.1) + toml (0.1.2) + parslet (~> 1.5.0) + train (0.23.0) + docker-api (~> 1.26) + json (>= 1.8, < 3.0) + mixlib-shellout (~> 2.0) + net-scp (~> 1.2) + net-ssh (>= 2.9, < 5.0) + winrm (~> 2.0) + winrm-fs (~> 1.0) + winrm (2.2.2) + builder (>= 2.1.2) + erubis (~> 2.7) + gssapi (~> 1.2) + gyoku (~> 1.0) + httpclient (~> 2.2, >= 2.2.0.2) + logging (>= 1.6.1, < 3.0) + nori (~> 2.0) + rubyntlm (~> 0.6.0, >= 0.6.1) + winrm-fs (1.0.1) + erubis (~> 2.7) + logging (>= 1.6.1, < 3.0) + rubyzip (~> 1.1) + winrm (~> 2.0) + +PLATFORMS + ruby + +DEPENDENCIES + kitchen-docker + kitchen-inspec + kitchen-salt + test-kitchen + +BUNDLED WITH + 1.14.6 diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..ea17c31 --- /dev/null +++ b/README.rst @@ -0,0 +1,62 @@ +====== +Vault +====== + +.. image:: https://travis-ci.org/saltstack-formulas/vault-formula.svg?branch=master + +Formulas for working with `Vault `_ + +Available states +================ + +.. contents:: + :local: + +``vault`` +---------- + +Install the vault binary + + +``vault.server`` +--------------------- + +Install and configure the vault server + +To use it, just include *vault.server* in your *top.sls*, and configure it using pillars: + +:: + + vault: + vault_version: 0.7.0 + listen_protocol: tcp + listen_port: 8200 + listen_address: 0.0.0.0 + strict_tls: 0 + default_lease_ttl: 24h + max_lease_ttl: 24h + self_signed_cert: + enabled: false + backend: {} + dev_mode: true + service: + type: systemd + +Testing +======= + +Testing is done with `Test Kitchen `_ +for machine setup and `inspec `_ +for integration tests. + +Requirements +------------ + +* Ruby +* Docker + +:: + + gem install bundler + bundle install + bundle exec kitchen test all diff --git a/pillar.example b/pillar.example index eaca2c7..4e67e56 100644 --- a/pillar.example +++ b/pillar.example @@ -1,11 +1,16 @@ vault: - vault_version: 0.7.0 - source_hash: c6d97220e75335f75bd6f603bb23f1f16fe8e2a9d850ba59599b1a0e4d067aaa + version: 0.7.0 listen_protocol: tcp listen_port: 8200 listen_address: 0.0.0.0 strict_tls: 0 - default_lease_ttl: '4380h' - max_lease_ttl: '43800h' - s3_backend: - bucket: 'com-foo-vault' + tls_cert_file: {} + tls_key_file: {} + default_lease_ttl: 4380h + max_lease_ttl: 43800h + self_signed_cert: + enabled: false + backend: {} + dev_mode: true + service: + type: upstart diff --git a/test/integration/default/vault_spec.rb b/test/integration/default/vault_spec.rb new file mode 100644 index 0000000..b27fa42 --- /dev/null +++ b/test/integration/default/vault_spec.rb @@ -0,0 +1,6 @@ +describe command('/usr/local/bin/vault -version') do + its(:exit_status) { should eq 0 } + its(:stderr) { should be_empty } + its(:stdout) { should match(/^Vault v[0-9\.]+ \('[0-9a-f]+'\)/) } +end + diff --git a/test/integration/dev_server_systemd/vault_spec.rb b/test/integration/dev_server_systemd/vault_spec.rb new file mode 100644 index 0000000..bdef182 --- /dev/null +++ b/test/integration/dev_server_systemd/vault_spec.rb @@ -0,0 +1,35 @@ +describe file('/etc/vault/config/server.hcl') do + it { should be_a_file } + expected =<<-EOF +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 0 + +} + +default_lease_ttl="24h" +max_lease_ttl="24h" +EOF + its(:content) { should eq(expected) } +end + +describe file('/etc/systemd/system/vault.service') do + it { should be_a_file } + its(:content) { should_not match /syslog/ } +end + +describe file('/etc/init/vault.conf') do + it { should_not be_a_file } +end + +describe service('vault') do + it { should be_enabled } + it { should be_running } +end + +describe command('journalctl -u vault') do + its(:exit_status) { should eq 0 } + its(:stderr) { should be_empty } + its(:stdout) { should match(/WARNING: Dev mode is enabled!/) } +end + diff --git a/test/integration/dev_server_upstart/vault_spec.rb b/test/integration/dev_server_upstart/vault_spec.rb new file mode 100644 index 0000000..1e8db72 --- /dev/null +++ b/test/integration/dev_server_upstart/vault_spec.rb @@ -0,0 +1,50 @@ +describe file('/etc/vault/config/server.hcl') do + it { should be_a_file } + expected = <<-EOF +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 0 + +} + +default_lease_ttl="24h" +max_lease_ttl="24h" +EOF + its(:content) { should eq(expected) } +end + +describe file('/etc/systemd/system/vault.service') do + it { should_not be_a_file } +end + +describe file('/etc/init/vault.conf') do + it { should be_a_file } + its(:content) { should_not match /syslog/ } +end + +if os[:family] == 'amazon' + # serverspec assumes 'service' resource to be + # init.d for rhel-based os. have to just check + # that it is running, that means that it started + # with the instance + describe command('sudo initctl list | grep vault | grep -v grep') do + its(:stdout) { should match(/vault start\/running/) } + its(:stderr) { should be_empty } + end + + describe processes("vault") do + its('users') { should eq ['root'] } + end + +else + describe service('vault') do + it { should be_enabled } + it { should be_running } + end +end + +describe file('/var/log/vault.log') do + it { should be_a_file } + its(:content) { should match(/WARNING: Dev mode is enabled!/) } +end + diff --git a/test/integration/server_backend_s3/vault_spec.rb b/test/integration/server_backend_s3/vault_spec.rb new file mode 100644 index 0000000..af2a05a --- /dev/null +++ b/test/integration/server_backend_s3/vault_spec.rb @@ -0,0 +1,36 @@ +describe file('/etc/vault/config/server.hcl') do + it { should be_a_file } + its(:content) { should match /bucket = "com-saltstack-vault"/ } +end + +describe file('/etc/init/vault.conf') do + it { should be_a_file } + its(:content) { should_not match /syslog/ } +end + +if os[:family] == 'amazon' + # serverspec assumes 'service' resource to be + # init.d for rhel-based os. have to just check + # that it is running, that means that it started + # with the instance + describe command('sudo initctl list | grep vault | grep -v grep') do + its(:stdout) { should match(/vault start\/running/) } + its(:stderr) { should be_empty } + end + + describe processes("vault") do + its('users') { should eq ['root'] } + end + +else + describe service('vault') do + it { should be_enabled } + it { should be_running } + end +end + +describe file('/var/log/vault.log') do + it { should be_a_file } + its(:content) { should match(/WARNING: Dev mode is enabled!/) } +end + diff --git a/vault/defaults.yaml b/vault/defaults.yaml new file mode 100644 index 0000000..5dc73dc --- /dev/null +++ b/vault/defaults.yaml @@ -0,0 +1,17 @@ +vault: + version: 0.7.0 + listen_protocol: tcp + listen_port: 8200 + listen_address: 0.0.0.0 + strict_tls: 0 + service: upstart + tls_cert_file: {} + tls_key_file: {} + default_lease_ttl: 24h + max_lease_ttl: 24h + self_signed_cert: + enabled: false + backend: {} + dev_mode: true + service: + type: systemd diff --git a/vault/files/server.hcl.jinja b/vault/files/server.hcl.jinja index c927079..41355f5 100644 --- a/vault/files/server.hcl.jinja +++ b/vault/files/server.hcl.jinja @@ -1,27 +1,25 @@ -{% from "vault/map.jinja" import vault with context %} - -{% if vault.s3_backend %} +{%- from "vault/map.jinja" import vault with context -%} +{%- if vault.backend and vault.backend.type == "s3" %} backend "s3" { - bucket = "{{ vault.s3_backend.bucket }}" + bucket = "{{ vault.backend.bucket }}" } -{% endif %} +{% endif -%} listener "{{ vault.listen_protocol }}" { address = "{{ vault.listen_address }}:{{ vault.listen_port }}" - tls_disable = {{ vault.strict_tls }} - {% if vault.self_signed_cert.enabled %} + tls_disable = {{ vault.strict_tls }} +{% if vault.self_signed_cert.enabled %} tls_cert_file = "/etc/vault/{{ vault.self_signed_cert.hostname }}.pem" tls_key_file = "/etc/vault/{{ vault.self_signed_cert.hostname }}-nopass.key" - {% else %} - {% if vault.tls_cert_file %} +{% else %} +{%- if vault.tls_cert_file %} tls_cert_file = "{{ vault.tls_cert_file }}" - {% endif %} - {% if vault.tls_key_file %} - tls_key_file = "{{ vault.tls_cert_file }}" - {% endif %} - {% endif %} +{% endif -%} +{%- if vault.tls_key_file %} + tls_key_file = "{{ vault.tls_key_file }}" +{% endif -%} +{% endif %} } -#todo parameterize default_lease_ttl="{{ vault.default_lease_ttl }}" max_lease_ttl="{{ vault.max_lease_ttl }}" diff --git a/vault/files/vault_systemd.service.jinja b/vault/files/vault_systemd.service.jinja new file mode 100644 index 0000000..7042a30 --- /dev/null +++ b/vault/files/vault_systemd.service.jinja @@ -0,0 +1,10 @@ +{%- from "vault/map.jinja" import vault with context -%} +[Unit] +Description=vault server +Requires=network-online.target +After=network-online.target consul.service + +[Service] +EnvironmentFile=-/etc/sysconfig/vault +Restart=on-failure +ExecStart=/usr/local/bin/vault server {% if vault.dev_mode %}-dev{% else %} -config="/etc/vault/config/server.hcl"{% endif %} diff --git a/vault/files/vault.conf.jinja b/vault/files/vault_upstart.conf.jinja similarity index 78% rename from vault/files/vault.conf.jinja rename to vault/files/vault_upstart.conf.jinja index 174db28..0feb2f5 100644 --- a/vault/files/vault.conf.jinja +++ b/vault/files/vault_upstart.conf.jinja @@ -1,3 +1,4 @@ +{%- from "vault/map.jinja" import vault with context -%} description "Vault server" start on (runlevel [345] and started network) @@ -14,6 +15,10 @@ script export GOMAXPROCS=`nproc` exec /usr/local/bin/vault server \ +{%- if vault.dev_mode %} + -dev \ +{% else %} -config="/etc/vault/config/server.hcl" \ +{% endif -%} >>/var/log/vault.log 2>&1 end script diff --git a/vault/init.sls b/vault/init.sls index 2349f0e..045d200 100644 --- a/vault/init.sls +++ b/vault/init.sls @@ -1,8 +1,20 @@ -{%- set version = salt.pillar.get('vault:vault_version', '0.7.0') %} -{%- set source_hash = salt.pillar.get('vault:source_hash', 'c6d97220e75335f75bd6f603bb23f1f16fe8e2a9d850ba59599b1a0e4d067aaa') %} -install Vault: - archive.extracted: - - name: /usr/local/bin - - source: https://releases.hashicorp.com/vault/{{ version }}/vault_{{ version }}_linux_amd64.zip - - source_hash: {{ source_hash }} - - enforce_toplevel: False +{% from "vault/map.jinja" import vault with context %} +# using archive.extracted causes: 'Comment: Failed to cache https://releases.hashicorp.com/vault/0.7.0/vault_0.7.0_linux_amd64.zip: [Errno 1] _ssl.c:493: error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version' +vault packages: + pkg.installed: + - names: + - unzip + - curl + +download vault: + cmd.run: + - name: curl --silent -L https://releases.hashicorp.com/vault/{{ vault.version }}/vault_{{ vault.version }}_linux_amd64.zip -o /tmp/vault.zip + - unless: test -e /tmp/vault.zip + +install vault: + cmd.run: + - name: unzip /tmp/vault.zip -d /usr/local/bin && chmod 0755 /usr/local/bin/vault && chown root:root /usr/local/bin/vault + - require: + - cmd: download vault + - pkg: unzip + - unless: test -e /usr/local/bin/vault diff --git a/vault/map.jinja b/vault/map.jinja index 5d5200c..3c3da4f 100644 --- a/vault/map.jinja +++ b/vault/map.jinja @@ -1,14 +1,2 @@ -{% set vault = salt['grains.filter_by']({ - 'default': { - listen_protocol: 'tcp', - listen_address: 0.0.0.0, - listen_port: 8200, - strict_tls: 1, - default_lease_ttl: '72h', - max_lease_ttl: '72h', - vault_version: '0.7.0', - self_signed_cert: { - enabled: false, - } - }, -}, merge=salt['pillar.get']('vault:lookup')) %} +{% import_yaml "vault/defaults.yaml" as defaults %} +{% set vault = salt['pillar.get']('vault', default=defaults['vault'], merge=True) %} diff --git a/vault/server.sls b/vault/server.sls index 33d2c26..15dc4ba 100644 --- a/vault/server.sls +++ b/vault/server.sls @@ -1,5 +1,5 @@ {% from "vault/map.jinja" import vault with context %} -{% if vault.self_signed_cert.enabled %} +{%- if vault.self_signed_cert.enabled %} /usr/local/bin/self-cert-gen.sh: file.managed: - source: salt://vault/files/cert-gen.sh.jinja @@ -14,7 +14,22 @@ generate self signed SSL certs: - cwd: /etc/vault - require: - file: /usr/local/bin/self-cert-gen.sh -{% endif %} +{% endif -%} + +/etc/vault: + file.directory: + - user: root + - group: root + - mode: 755 + +{%- if vault.dev_mode %} +/etc/vault/config: + file.directory: + - user: root + - group: root + - mode: 755 + - require: + - file: /etc/vault /etc/vault/config/server.hcl: file.managed: @@ -23,21 +38,39 @@ generate self signed SSL certs: - user: root - group: root - mode: 644 + - require: + - file: /etc/vault/config +{% endif -%} -/etc/init/vault.conf: +{%- if vault.service.type == 'systemd' %} +/etc/systemd/system/vault.service: file.managed: - - source: salt://vault/files/vault.conf.jinja + - source: salt://vault/files/vault_systemd.service.jinja - template: jinja - user: root - group: root - mode: 644 + - require_in: + - service: vault + +{% elif vault.service.type == 'upstart' %} +/etc/init/vault.conf: + file.managed: + - source: salt://vault/files/vault_upstart.conf.jinja + - template: jinja + - user: root + - group: root + - require_in: + - service: vault +{% endif -%} vault: service.running: - enable: True - require: - {% if vault.self_signed_cert.enabled %} + {%- if vault.self_signed_cert.enabled %} - cmd: generate self signed SSL certs - {% endif %} + {% endif -%} + {%- if vault.dev_mode %} - file: /etc/vault/config/server.hcl - - file: /etc/init/vault.conf + {% endif -%}