vault-provision

Vault-Provision

The Ansible role for install and configure vault and then provision variables on it. Module supports RHEL/Centos6+7/Fedora for now. The role will be extended in the future and will support Debian/Ubuntu and other operating systems.

Requirements

This role requires Ansible 2.0 or higher.

Role Variables

Variable part is devided into three sections:

General part

### ########################################################### ###
### General section                                             ###
### ########################################################### ###

vault_token: "{{ lookup('env', 'VAULT_TOKEN') }}" # token to provision vault is taken from environment variables, unless you provide vault_token by extra vars or you override this value by your ansible variable

vault_app_mirror: 'https://releases.hashicorp.com' # Package repository
vault_app_platform: 'linux_amd64' # Which one platform are you interested in 
vault_app_install_dir: '/opt/vault' # Instalation directory where vault will be installed

vault_app: vault # Vault zip package name
vault_app_ver: '0.6.4' # Version of vault application
vault_app_checksum: sha256:04d87dd553aed59f3fe316222217a8d8777f40115a115dac4d88fac1611c51a6 # Checksum of the Vault zip package

vault_app_name : '{{vault_app}}_{{vault_app_ver}}_{{vault_app_platform}}' # Vault's package name to download
vault_app_zip : '{{vault_app_name}}.zip' # Vault's zip package to download
vault_app_url : '{{vault_app_mirror}}/{{vault_app}}/{{vault_app_ver}}/{{vault_app_zip}}' # Full URL to get the Vault package

method: http # Whether https or http should be use for provisioning process
vault_domain_name: vault.your.domain # Vault domain name or ip address
vault_api_version: v1 # Vault's REST API version
content_type: application/json # The content type of the http body request

vault_user: vault # Group which is allowed to run vault service
vault_group: vault # User which is allowed to run vault service

vault_service_enabled: true # Controls whether service automatically started

backend_type: file # backend used by you. All possible supported backends are listed at [`https://www.vaultproject.io/docs/config/index.html`](https://www.vaultproject.io/docs/config/index.html).

Configuration part

Variables for Configuration part are well described at vault website https://www.vaultproject.io/docs/config/index.html. Basicly variable names in this module reflect these in vault config documentation. You can define more than one vault_configuration.backend variable but just one will be use and you have to specify which one in backend_type variable in general section. The module is flexible and backend_type variable can be whatever backend which is supperted by Vault. In your config please keep only variables which is used by you. Rest of the variables can be commented out or just removed. For now all possible configuration variables are mention below:

### ########################################################### ###
### Configuration section                                       ###
### ########################################################### ###

vault_configuration:
  backend:
    consul:
      path: vault
      address: 127.0.0.1:8500
      scheme:
      check_timeout:
      disable_registration:
      service:
      service_tags:
      token:
      max_parallel:
      consistency_mode:
      tls_skip_verify:
      tls_min_version:
      tls_ca_file:
      tls_cert_file:
      tls_key_file:
    etcd:
      path:
      address:
      sync:
      ha_enabled:
      username:
      password:
      tls_ca_file:
      tls_cert_file:
      tls_key_file:
    zookeeper:
      path:
      address:
      auth_info:
      znode_owner:
    dynamodb:
      access_key:
      secret_key:
      table:
      read_capacity:
      write_capacity:
      session_token:
      endpoint:
      region:
      max_parallel:
      ha_enabled:
      recovery_mode:
    s3:
      bucket: bucket_name
      access_key: AKIAJWVN5Z4FOFT7NLNA
      secret_key: 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
      session_token:
      endpoint:
      region: us-east-1
    gcs:
      bucket:
      credentials_file:
      max_parallel:
    azure:
      accountName:
      accountKey:
      container:
      max_parallel:
    swift:
      container:
      username:
      password:
      auth_url:
      tenant:
      max_parallel:
    mysql:
      username:
      password:
      address:
      database:
      table:
      tls_ca_file:
    postgresql:
      connection_url:
      table:
    inmem:
    file:
      path: /opt/vault/storage
    ha_options:
      redirect_addr:
      cluster_addr:
      disable_clustering:
  listener: #"tcp" and "atlas" are valid values
    tcp:
      address: 0.0.0.0:8200
      tls_disable: 1
      cluster_address:
      tls_cert_file:
      tls_key_file:
      tls_min_version:
    atlas:
      endpoint:
      infrastructure:
      node_id:
      token:
    telemetry:
      statsite_address:
      statsd_address:
      disable_hostname:
      circonus_api_token:
      circonus_api_app:
      circonus_api_url:
      circonus_submission_interval:
      circonus_submission_url:
      circonus_check_id:
      circonus_check_force_metric_activation:
      circonus_check_instance_id:
      circonus_check_search_tag:
      circonus_check_display_name:
      circonus_check_tags:
      circonus_broker_id:
      circonus_broker_select_tag:
  ha_backend:
  cluster_name:
  cache_size:
  disable_cache: false
  disable_mlock: false
  default_lease_ttl:
  max_lease_ttl:
  ui:

Provision part

### ########################################################### ###
### Provision section                                           ###
### ########################################################### ###

backends: # Define backends which will be created
  - backend_name: secret # Backend named secret will be created if doesn't exist
    configuration:
      type: generic # Type of the backend
      description: This backend stores credentials of users # Description
      config:
        max_lease_ttl: 4000 # Max TTL time
    path: secret # Vault internal path where backend will be mounted 
    secrets: # Set of data container which will be created
      - container_name: authcredentials # Data container named authcredentials
        data: # Comprise all keys and values which will be provisioned into secret/authcredentials
          username: password 
          david: superstrongpasswordfordavid
          daniel: superstrongpasswordfordaniel
      - container_name: privatekeys # Data container named privatekeys
        data: # Comprise all keys and values which will be provisioned into secret/privatekeys
          key_name: encryptedkey
          key_for_mail: enctryptedkeyformail
  - backend_name: test # Backend named test will be created if doesn't exist
    configuration:
      type: generic # Type of the backend
    path: test # Vault internal path where backend will be mounted
    secrets: # Set of data container which will be created
      - container_name: test_container # Data container named test_container
        data: # Comprise all keys and values which will be provisioned into test/test_container
          important_data: importantdatavalue
          another_important_data: anotherimportantdatavalue

initialization: # PGP keys for initialization process
  root_token_pgp_key: mQENBFhZFd4BCADGj9gcnJHRwQk1UL8BxTugxmJ6uk82S837LWqzrsDv18zObBQK8bmTFps4x6DrUbLbxzHRB7kxbR5g/KN2qCqMYcYkKgLqMqo9XaS4vCriQKCFaZ3FWG99/TxUurPpy+crVCDun8UMGmWZCvRu7UBJQsAF1htukVhdEXAd1116WRD6W5k/+X6B6FvSAD7ud/PWUENdtLxiRgBVhRCHWPlJvdA7I7EaBjF5TMbwFP4wlSHxbdrWZ0z9wGk5FFbtl1qlNaojyJR1Gs3a7T7lB7y1dr6Y727JAYHP5uzQo06F0nfQm58sXtmeBnyhOHZ04BzXBik+Uoh9Bh1Uj7em0cP5ABEBAAG0T0tyenlzenRvZiBTemV3Y3p5ayAoRW5jcnlwdGlvbiBrZXkgZm9yIEhhc2hpY29ycCBWYXVsdCkgPGsuc3pld2N6eWtAa2Fpbm9zLmNvbT6JAT4EEwECACgFAlhZFd4CGwMFCQHhM4AGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMOj6FrFv4ik9bsH/3gmLKh8r2xhsbA79bEzBjNPDX9G6qeHfea+RMRjLH5yvNH9/Hnjwkqn3LIAdpzacldrjZMEpqS5z310gxk+cyNB/dFe/Wqmh1UQljDQ354qAZAtQ7OLuypVsg+tI8aIRQieCEC4Ck/h8xnAK8AoOHb29vR+BMNdqp+TNrDrAeYAKchmJiWcYxt5YqT4AP5JRzT82o2Sms3ihyFe1KxgcNbrNjJpEMoCnu8l5e1RrlIeMU8Hm5Mms1ZvausPfFlsa76shhOCZMfZ2acsuuTRqx8ed8UrSmDqAiia60BupsfRfMkqf/GdkEEESoRKhz1EHAUQiC9Flshyl/CjWqCIQCi5AQ0EWFkV3gEIAKLrtH904COoJhOjdqUQNSGu0TSsNik2Hd/v5A5KxG7a2iiqLOD73VvINaTHpwUjkWR3OcgRuqsnshST/qg3T1t8gghON70Pg6nKEPbDGabhA19fQ64woSvY6I2ZTv/XY0CxxDAVNN2O3rpl6ZnUgQBVjd/u4Nx3cydf30MnPtipb9bJ1ISZvWtMAYxAeiqd/6rcj/BXSQBt05ffDwPBd5+7pL7gQrJTa51icggKq06KwTfSdi0cPmqvOenKZB0exrp2jtxw1+QIhlhJJyv33fxaJHZaFqlh7vn6j7e03J4UaVPl5h/fnNg3i1uJJW9E6ECfAwRy394r7V1LUZ/GiEMAEQEAAYkBJQQYAQIADwUCWFkV3gIbDAUJAeEzgAAKCRDDo+haxb+IpJFmB/99Ss1U/dJA/XFwWofj3iEDM3W7OJoahYJLD7eOo3lPT8vNnLEVOPkSPjvaggkSsM3Xp5WZw2/oQ3p5KuIE2bSGK/Ok8zEAjEbn5vT4GNTBSH070OAQEHD5dEcYmh9EKSnitPXlLMOG/szsnReimBjLXRibU2wvuMeY7QO58K9kHm1K9cpNWuU5h8M4CMlBATvfl4ZeIBm6K9gmqKKxkF+7Mw1U8XG/OZv6GQwbMER3h7cdsor9LsOZTIdZW7bj9Iyh42hZHMcWq1E2VvHuklwJdpZfKlUs6b/6WwSPsypLLfHnO6C/G726MXH2JuZe5/fFpn+skxgbYNZ1y1BTnyvs # Public part of PGP key for vault root token encryption. After initialization process outputted root token is encrypted by this PGP public key
  secret_threshold: 1 # Define how many keys is required to unseal the vault (This value have to be less then length of the below pgp_keys array )
  pgp_keys: # Array defined how many keys will be created. The keys will be encrypted by below PGP keys
   - mQENBFhZFd4BCADGj9gcnJHRwQk1UL8BxTugxmJ6uk82S837LWqzrsDv18zObBQK8bmTFps4x6DrUbLbxzHRB7kxbR5g/KN2qCqMYcYkKgLqMqo9XaS4vCriQKCFaZ3FWG99/TxUurPpy+crVCDun8UMGmWZCvRu7UBJQsAF1htukVhdEXAd1116WRD6W5k/+X6B6FvSAD7ud/PWUENdtLxiRgBVhRCHWPlJvdA7I7EaBjF5TMbwFP4wlSHxbdrWZ0z9wGk5FFbtl1qlNaojyJR1Gs3a7T7lB7y1dr6Y727JAYHP5uzQo06F0nfQm58sXtmeBnyhOHZ04BzXBik+Uoh9Bh1Uj7em0cP5ABEBAAG0T0tyenlzenRvZiBTemV3Y3p5ayAoRW5jcnlwdGlvbiBrZXkgZm9yIEhhc2hpY29ycCBWYXVsdCkgPGsuc3pld2N6eWtAa2Fpbm9zLmNvbT6JAT4EEwECACgFAlhZFd4CGwMFCQHhM4AGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMOj6FrFv4ik9bsH/3gmLKh8r2xhsbA79bEzBjNPDX9G6qeHfea+RMRjLH5yvNH9/Hnjwkqn3LIAdpzacldrjZMEpqS5z310gxk+cyNB/dFe/Wqmh1UQljDQ354qAZAtQ7OLuypVsg+tI8aIRQieCEC4Ck/h8xnAK8AoOHb29vR+BMNdqp+TNrDrAeYAKchmJiWcYxt5YqT4AP5JRzT82o2Sms3ihyFe1KxgcNbrNjJpEMoCnu8l5e1RrlIeMU8Hm5Mms1ZvausPfFlsa76shhOCZMfZ2acsuuTRqx8ed8UrSmDqAiia60BupsfRfMkqf/GdkEEESoRKhz1EHAUQiC9Flshyl/CjWqCIQCi5AQ0EWFkV3gEIAKLrtH904COoJhOjdqUQNSGu0TSsNik2Hd/v5A5KxG7a2iiqLOD73VvINaTHpwUjkWR3OcgRuqsnshST/qg3T1t8gghON70Pg6nKEPbDGabhA19fQ64woSvY6I2ZTv/XY0CxxDAVNN2O3rpl6ZnUgQBVjd/u4Nx3cydf30MnPtipb9bJ1ISZvWtMAYxAeiqd/6rcj/BXSQBt05ffDwPBd5+7pL7gQrJTa51icggKq06KwTfSdi0cPmqvOenKZB0exrp2jtxw1+QIhlhJJyv33fxaJHZaFqlh7vn6j7e03J4UaVPl5h/fnNg3i1uJJW9E6ECfAwRy394r7V1LUZ/GiEMAEQEAAYkBJQQYAQIADwUCWFkV3gIbDAUJAeEzgAAKCRDDo+haxb+IpJFmB/99Ss1U/dJA/XFwWofj3iEDM3W7OJoahYJLD7eOo3lPT8vNnLEVOPkSPjvaggkSsM3Xp5WZw2/oQ3p5KuIE2bSGK/Ok8zEAjEbn5vT4GNTBSH070OAQEHD5dEcYmh9EKSnitPXlLMOG/szsnReimBjLXRibU2wvuMeY7QO58K9kHm1K9cpNWuU5h8M4CMlBATvfl4ZeIBm6K9gmqKKxkF+7Mw1U8XG/OZv6GQwbMER3h7cdsor9LsOZTIdZW7bj9Iyh42hZHMcWq1E2VvHuklwJdpZfKlUs6b/6WwSPsypLLfHnO6C/G726MXH2JuZe5/fFpn+skxgbYNZ1y1BTnyvs # Public part of PGP key for Vault key encryption.

policies: # Array of the policies that will be created
  - name: testpolicy # Name of the policy
    data: # Contain rules
      rules: "path \"secret/authcredentials\" {\n  policy = \"read\"\n}\npath \"test/test_container\" {\n  policy = \"read\"\n}\npath \"auth/token/lookup-self\" {\n  policy = \"read\"\n}" # Contain rules in plaintext HCL format

tokens: # Array of the tokens that will be created
  - display_name: test_token # Name of the token
    id: 950938df-50cb-7a24-faeh-b4f2a23g3b6f # Id of the token
    policies: # Array of the policies attached to token
      - testpolicy # Name of the policy attached to token

Another required variables:

During the first cycle of running this role the initialization process is performed. The unseal keys and vault root token are outputted and these values are encrypted by pgp_keys. The provisioning process is skipped. You have to depcypt the unseal keys. Then you have to unseal in some way (ssh to the machine and unseal vault by providing the decrypted keys or you define some job in continues integration tool which do it for you). The way how would you like to do it is up to you.

When you have Vault unsealed then decrypt vault root token and put decrypted value as a vault_token variable. Then you can define this value in your ansible in vars or set VAULT_TOKEN environment variable or call ansible with extra vars parameter like this:

ansible-playbook -i "<ip_address>," vault.yml --extra-vars '{"vault_token":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"}'

or the other way is to store vault_token value in continues integration tool and pass this value in your jenkins job or Jenkinsfile like this:

withCredentials([[$class: 'StringBinding', credentialsId: 'vault_token', variable: 'VAULT_TOKEN']])
  {
    sh '''
    ansible-playbook ./master.yml -i "<ip_address>," --extra-vars "env=$ENV"
    '''
  }

If you provide correct vault token and the vault is unsealed, during the second cycle the role will provision the vault. All backends, containers, keys and values, policies, tokens will be created.

Dependencies

The role has no external dependencies.

Example Playbook

You have to at least define your own variables in your playbook:

method: http # Suggest to use https
vault_domain_name: vault.your.domain
vault_configuration:
  backend:
    file:
      path: /opt/vault/storage
  listener: #"tcp" and "atlas" are valid values
    tcp:
      address: 0.0.0.0:8200
      tls_disable: 1
  disable_cache: false
  disable_mlock: false

You have to also define backends, secrets, policies which you would like to put into Vault and of course you have to define some initialization values like pgp keys for Vault keys encryption, pgp key for Vault root token encryption and secret threshold which define how many keys you/your team have to provide to unseal the Vault. Secret threshold must be less than length of the pgp_keys array. Let's adopt below variables as you want.

  - backend_name: secret
    configuration:
      type: generic
      description: This backend stores credentials of users
      config:
        max_lease_ttl: 4000
    path: secret
    secrets:
      - container_name: authcredentials
        data:
          username: password
          david: superstrongpasswordfordavid
          daniel: superstrongpasswordfordaniel
      - container_name: privatekeys
        data:
          key_name: encryptedkey
          key_for_mail: enctryptedkeyformail
  - backend_name: test
    configuration:
      type: generic
      #description:
      #config:
        #max_lease_ttl:
    path: test
    secrets:
      - container_name: test_container
        data:
          important_data: importantdatavalue
          another_important_data: anotherimportantdatavalue

initialization:
  root_token_pgp_key: mQENBFhZFd4BCADGj9gcnJHRwQk1UL8BxTugxmJ6uk82S837LWqzrsDv18zObBQK8bmTFps4x6DrUbLbxzHRB7kxbR5g/KN2qCqMYcYkKgLqMqo9XaS4vCriQKCFaZ3FWG99/TxUurPpy+crVCDun8UMGmWZCvRu7UBJQsAF1htukVhdEXAd1116WRD6W5k/+X6B6FvSAD7ud/PWUENdtLxiRgBVhRCHWPlJvdA7I7EaBjF5TMbwFP4wlSHxbdrWZ0z9wGk5FFbtl1qlNaojyJR1Gs3a7T7lB7y1dr6Y727JAYHP5uzQo06F0nfQm58sXtmeBnyhOHZ04BzXBik+Uoh9Bh1Uj7em0cP5ABEBAAG0T0tyenlzenRvZiBTemV3Y3p5ayAoRW5jcnlwdGlvbiBrZXkgZm9yIEhhc2hpY29ycCBWYXVsdCkgPGsuc3pld2N6eWtAa2Fpbm9zLmNvbT6JAT4EEwECACgFAlhZFd4CGwMFCQHhM4AGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMOj6FrFv4ik9bsH/3gmLKh8r2xhsbA79bEzBjNPDX9G6qeHfea+RMRjLH5yvNH9/Hnjwkqn3LIAdpzacldrjZMEpqS5z310gxk+cyNB/dFe/Wqmh1UQljDQ354qAZAtQ7OLuypVsg+tI8aIRQieCEC4Ck/h8xnAK8AoOHb29vR+BMNdqp+TNrDrAeYAKchmJiWcYxt5YqT4AP5JRzT82o2Sms3ihyFe1KxgcNbrNjJpEMoCnu8l5e1RrlIeMU8Hm5Mms1ZvausPfFlsa76shhOCZMfZ2acsuuTRqx8ed8UrSmDqAiia60BupsfRfMkqf/GdkEEESoRKhz1EHAUQiC9Flshyl/CjWqCIQCi5AQ0EWFkV3gEIAKLrtH904COoJhOjdqUQNSGu0TSsNik2Hd/v5A5KxG7a2iiqLOD73VvINaTHpwUjkWR3OcgRuqsnshST/qg3T1t8gghON70Pg6nKEPbDGabhA19fQ64woSvY6I2ZTv/XY0CxxDAVNN2O3rpl6ZnUgQBVjd/u4Nx3cydf30MnPtipb9bJ1ISZvWtMAYxAeiqd/6rcj/BXSQBt05ffDwPBd5+7pL7gQrJTa51icggKq06KwTfSdi0cPmqvOenKZB0exrp2jtxw1+QIhlhJJyv33fxaJHZaFqlh7vn6j7e03J4UaVPl5h/fnNg3i1uJJW9E6ECfAwRy394r7V1LUZ/GiEMAEQEAAYkBJQQYAQIADwUCWFkV3gIbDAUJAeEzgAAKCRDDo+haxb+IpJFmB/99Ss1U/dJA/XFwWofj3iEDM3W7OJoahYJLD7eOo3lPT8vNnLEVOPkSPjvaggkSsM3Xp5WZw2/oQ3p5KuIE2bSGK/Ok8zEAjEbn5vT4GNTBSH070OAQEHD5dEcYmh9EKSnitPXlLMOG/szsnReimBjLXRibU2wvuMeY7QO58K9kHm1K9cpNWuU5h8M4CMlBATvfl4ZeIBm6K9gmqKKxkF+7Mw1U8XG/OZv6GQwbMER3h7cdsor9LsOZTIdZW7bj9Iyh42hZHMcWq1E2VvHuklwJdpZfKlUs6b/6WwSPsypLLfHnO6C/G726MXH2JuZe5/fFpn+skxgbYNZ1y1BTnyvs
  secret_threshold: 1
  pgp_keys:
   - mQENBFhZFd4BCADGj9gcnJHRwQk1UL8BxTugxmJ6uk82S837LWqzrsDv18zObBQK8bmTFps4x6DrUbLbxzHRB7kxbR5g/KN2qCqMYcYkKgLqMqo9XaS4vCriQKCFaZ3FWG99/TxUurPpy+crVCDun8UMGmWZCvRu7UBJQsAF1htukVhdEXAd1116WRD6W5k/+X6B6FvSAD7ud/PWUENdtLxiRgBVhRCHWPlJvdA7I7EaBjF5TMbwFP4wlSHxbdrWZ0z9wGk5FFbtl1qlNaojyJR1Gs3a7T7lB7y1dr6Y727JAYHP5uzQo06F0nfQm58sXtmeBnyhOHZ04BzXBik+Uoh9Bh1Uj7em0cP5ABEBAAG0T0tyenlzenRvZiBTemV3Y3p5ayAoRW5jcnlwdGlvbiBrZXkgZm9yIEhhc2hpY29ycCBWYXVsdCkgPGsuc3pld2N6eWtAa2Fpbm9zLmNvbT6JAT4EEwECACgFAlhZFd4CGwMFCQHhM4AGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMOj6FrFv4ik9bsH/3gmLKh8r2xhsbA79bEzBjNPDX9G6qeHfea+RMRjLH5yvNH9/Hnjwkqn3LIAdpzacldrjZMEpqS5z310gxk+cyNB/dFe/Wqmh1UQljDQ354qAZAtQ7OLuypVsg+tI8aIRQieCEC4Ck/h8xnAK8AoOHb29vR+BMNdqp+TNrDrAeYAKchmJiWcYxt5YqT4AP5JRzT82o2Sms3ihyFe1KxgcNbrNjJpEMoCnu8l5e1RrlIeMU8Hm5Mms1ZvausPfFlsa76shhOCZMfZ2acsuuTRqx8ed8UrSmDqAiia60BupsfRfMkqf/GdkEEESoRKhz1EHAUQiC9Flshyl/CjWqCIQCi5AQ0EWFkV3gEIAKLrtH904COoJhOjdqUQNSGu0TSsNik2Hd/v5A5KxG7a2iiqLOD73VvINaTHpwUjkWR3OcgRuqsnshST/qg3T1t8gghON70Pg6nKEPbDGabhA19fQ64woSvY6I2ZTv/XY0CxxDAVNN2O3rpl6ZnUgQBVjd/u4Nx3cydf30MnPtipb9bJ1ISZvWtMAYxAeiqd/6rcj/BXSQBt05ffDwPBd5+7pL7gQrJTa51icggKq06KwTfSdi0cPmqvOenKZB0exrp2jtxw1+QIhlhJJyv33fxaJHZaFqlh7vn6j7e03J4UaVPl5h/fnNg3i1uJJW9E6ECfAwRy394r7V1LUZ/GiEMAEQEAAYkBJQQYAQIADwUCWFkV3gIbDAUJAeEzgAAKCRDDo+haxb+IpJFmB/99Ss1U/dJA/XFwWofj3iEDM3W7OJoahYJLD7eOo3lPT8vNnLEVOPkSPjvaggkSsM3Xp5WZw2/oQ3p5KuIE2bSGK/Ok8zEAjEbn5vT4GNTBSH070OAQEHD5dEcYmh9EKSnitPXlLMOG/szsnReimBjLXRibU2wvuMeY7QO58K9kHm1K9cpNWuU5h8M4CMlBATvfl4ZeIBm6K9gmqKKxkF+7Mw1U8XG/OZv6GQwbMER3h7cdsor9LsOZTIdZW7bj9Iyh42hZHMcWq1E2VvHuklwJdpZfKlUs6b/6WwSPsypLLfHnO6C/G726MXH2JuZe5/fFpn+skxgbYNZ1y1BTnyvs

policies:
  - name: testpolicy
    data:
      rules: "path \"secret/authcredentials\" {\n  policy = \"read\"\n}\npath \"test/test_container\" {\n  policy = \"read\"\n}\npath \"auth/token/lookup-self\" {\n  policy = \"read\"\n}"

tokens:
  - display_name: test_token
    id: 950938df-50cb-7a24-faeh-b4f2a23g3b6f
    policies:
      - testpolicy

Playbook can look like:

---
- name: Provision vault
  hosts: vault.your.domain
  roles:
  - vault-provision

Decrypt Vault keys and root token

During the first cycle of provisioning you get keys and root token:

TASK [vault-provision : debug] *************************************************
ok: [vaultprovision] => {
    "initialization": {
        "cache_control": "no-store",
        "changed": false,
        "connection": "close",
        "content_length": "1899",
        "content_type": "application/json",
        "date": "Wed, 28 Dec 2016 17:56:58 GMT",
        "json": {
            "keys": [
                "c1c04c03822c554bc14d713401080024fc6ac55a5966819561129600f055d8fc837e3371955b586887408d3d82c2eb4c897678137daaa39fddc0b1062d199db654b69bce20aebbade8fc7b20d2cf9cafc129a5e321542f332d37ecc1357314ead64eaa25131723197b90827c7c63fb7465ba8ae1ef762cc7dcb583df7246d95c7593efae3f7391e39dcb023f9d7933d6a553d510e30c643dc78939218cef2bca650e20fe7aa494157bde4a0c26a733321a597adc2b65c59110d408c764f3cdcc3082beccb89ff3103e6cc1c81f83dc00628cd5201edc3d36f58d6c2921798b7d2803254ebe3414eeef2bb923a0baaa21016c57193ab6e9abfe2f7a0baf7181200980d9bab7f1f2cd12c80a43aad455d2e001e4cf59665b131fd56e5a793f0fd5670891e1fb87e0bfe0f7e16799e084e2352a6027e0dce66f4b05d594f172c58717660a4ea46adf3bc240e134950c07f0c302d1458f5dccc14d95fc669004891903cd1a5a9ac2dcd9f25564238990cda2e0e3a57006cf9de0f4e498ddc6d2349e201378da85eceb979fa6e246ae4ea7e174a100"
            ],
            "keys_base64": [
                "wcBMA4IsVUvBTXE0AQgAJPxqxVpZZoGVYRKWAPBV2PyDfjNxlVtYaIdAjT2CwutMiXZ4E32qo5/dwLEGLRmdtlS2m84grrut6Px7INLPnK/BKaXjIVQvMy037ME1cxTq1k6qJRMXIxl7kIJ8fGP7dGW6iuHvdizH3LWD33JG2Vx1k++uP3OR453LAj+deTPWpVPVEOMMZD3HiTkhjO8rymUOIP56pJQVe95KDCanMzIaWXrcK2XFkRDUCMdk883MMIK+zLif8xA+bMHIH4PcAGKM1SAe3D029Y1sKSF5i30oAyVOvjQU7u8ruSOguqohAWxXGTq26av+L3oLr3GBIAmA2bq38fLNEsgKQ6rUVdLgAeTPWWZbEx/Vblp5Pw/VZwiR4fuH4L/g9+FnmeCE4jUqYCfg3OZvSwXVlPFyxYcXZgpOpGrfO8JA4TSVDAfwwwLRRY9dzMFNlfxmkASJGQPNGlqawtzZ8lVkI4mQzaLg46VwBs+d4PTkmN3G0jSeIBN42oXs65efpuJGrk6n4XShAA=="
            ],
            "root_token": "wcBMA4IsVUvBTXE0AQgAGQNSD1geNeecOe2Pta7ugXaCIIf80HEX7YJPouys2x6SzB844GG+zCEubsswFBANOgTMctTExC0Fs35vRhCTZakAkYuRLIirQXuFOxZ7avIIaCsv/sn8/R3gIRNWSiRX/m2snI3r49UkA7tJo8w/BKS9b+SQwzDwCAMNY04gXqOE++bJqY6Z/PEEebhuv7McJrA+s2SJj8zKst5DgXzm5tNhkr5/McQEntcHG/RZHBKtBbHppSLDibd98TODnHkcEm+DkhYgKhNQNEiTYzOTHoZtdwwgwd6tYfPYV9d4z/3SsEnXmRskEymJONLU4uMo6nlykNq8UxsqW3vc/xCDhNLgAeTfuOJ86dRgq0Q+2m1wxwBU4Zb34ALg5eEehOCM4nEi8KjgJOWob3JV0y74SJy1tUlXvbIeT5RwvLimvueEbOwVc1FlsuBm4k8V8ATgquRHGMHaat72Z3Q4906BTGb14thk+abhPsYA"
        },
        "msg": "OK (1899 bytes)",
        "redirected": false,
        "status": 200,
        "url": "http://192.168.60.10:8200/v1/sys/init"
    }
}

In the keys_base64 array of the received json you can see your keys encrypted by the provided earlier PGP or GPG keys in base64 format. To decrypt that you have to decode your base64 formated value and then decrypt by gpg1 tool (MacOS) or gpg tool (Linux).

echo "wcBMA4IsVUvBTXE0AQgAJPxqxVpZZoGVYRKWAPBV2PyDfjNxlVtYaIdAjT2CwutMiXZ4E32qo5/dwLEGLRmdtlS2m84grrut6Px7INLPnK/BKaXjIVQvMy037ME1cxTq1k6qJRMXIxl7kIJ8fGP7dGW6iuHvdizH3LWD33JG2Vx1k++uP3OR453LAj+deTPWpVPVEOMMZD3HiTkhjO8rymUOIP56pJQVe95KDCanMzIaWXrcK2XFkRDUCMdk883MMIK+zLif8xA+bMHIH4PcAGKM1SAe3D029Y1sKSF5i30oAyVOvjQU7u8ruSOguqohAWxXGTq26av+L3oLr3GBIAmA2bq38fLNEsgKQ6rUVdLgAeTPWWZbEx/Vblp5Pw/VZwiR4fuH4L/g9+FnmeCE4jUqYCfg3OZvSwXVlPFyxYcXZgpOpGrfO8JA4TSVDAfwwwLRRY9dzMFNlfxmkASJGQPNGlqawtzZ8lVkI4mQzaLg46VwBs+d4PTkmN3G0jSeIBN42oXs65efpuJGrk6n4XShAA==" | base64 -D | gpg1 -d

The result of the above command will be your decrypted key which is necessary to unseal Vault.

Let's do the same with your root_token:

echo "wcBMA4IsVUvBTXE0AQgAGQNSD1geNeecOe2Pta7ugXaCIIf80HEX7YJPouys2x6SzB844GG+zCEubsswFBANOgTMctTExC0Fs35vRhCTZakAkYuRLIirQXuFOxZ7avIIaCsv/sn8/R3gIRNWSiRX/m2snI3r49UkA7tJo8w/BKS9b+SQwzDwCAMNY04gXqOE++bJqY6Z/PEEebhuv7McJrA+s2SJj8zKst5DgXzm5tNhkr5/McQEntcHG/RZHBKtBbHppSLDibd98TODnHkcEm+DkhYgKhNQNEiTYzOTHoZtdwwgwd6tYfPYV9d4z/3SsEnXmRskEymJONLU4uMo6nlykNq8UxsqW3vc/xCDhNLgAeTfuOJ86dRgq0Q+2m1wxwBU4Zb34ALg5eEehOCM4nEi8KjgJOWob3JV0y74SJy1tUlXvbIeT5RwvLimvueEbOwVc1FlsuBm4k8V8ATgquRHGMHaat72Z3Q4906BTGb14thk+abhPsYA" | base64 -D | gpg1 -d

The result of the above command will be your decrypted key which is necessary to further Vault provisioning process - deployment backends, tokens and secrets into Vault. Like i mentioned before root token will be necessary during the second cycle of Vault provisioning and you have to pass root token to ansible as an extra vars:

ansible-playbook -i "<ip_address>," vault.yml --extra-vars '{"vault_token":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"}'

Notice: If vault_token variable is empty then second provision cycle will be skipped.

Sample curl queries to debug vault on localhost

Check whether vault is initialized

curl -X GET http://127.0.0.1:8200/v1/sys/init

Vault initialization

Simple initialization without - root token and keys will be output in plaintext:

curl -X GET -d '{"secret_shares": 1, "secret_threshold": 1}' http://127.0.0.1:8200/v1/sys/init

Intialization with root token and keys encryption:

curl -X PUT -d '{"root_token_pgp_key":"mQENBFhZPkcBCADNApFjN/XvU/yeF4SRoHWzcEmummdMop6GiJg+ji//RPpCqzTY2ww3insb/2alLn7/V5LfuOIIfCFId76sWh0ckIXMdC9EOWlkmJi+Vlncq1Q/KRrE0WyUr8AaAFTbc51AAtUWWR9JW+0GwEpJxTkD9nwdU9Q5o+QKjj8BQ83UdzsnY8hUxSxnyiuufC+XWphUJLeXbJnKaaLs4gu/hoJ6SThEta2vg3B4nXGj3a3U3NuMnmzTlHbODB+bmhSjby68JKflgcQm8kpfxj/+56oX7fGn2xscWA8lBq3GkCFAqzf8j4S1+yJrLgI6//Qv1upYC9UbfYSkzhGPhOHvZL4BABEBAAG0QUtyenlzenRvZiBTemV3Y3p5ayAoRm9yIEhhc2hpb2NvcnAgVmF1bHQpIDxrLnN6ZXdjenlrQGthaW5vcy5jb20+iQE/BBMBAgApBQJYWT5HAhsDBQkDwmcABwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQdL+2Ckh/nsDrZgf/X4Rib24zkLd57TcaKa1/exbRXi5LvC9/EQKeBAr1+SjYqJptgxpZkjcLL3D3d7Uzj8PFHpDy4u8HSEunCG6WtOmeJcTocVIOB2sHor/4jGCazo/Q50mg4ui6totH55Jn0uCxjwB2Mv+ypbE6I9iI25srxkfo06t1tbPcGoGqxSvJdNSlemdmgOphjcIk5uuK5LWD8jbt6TYx66sb0Patl5i77pvuFrBnq8WWVNe1NUpO+oNggMfxaW2RMVYXJRC/S7eH6GIpsPo+h/S4V6037bfeVzUvRcYvdZvL3PQpI7QehweUw6I96SCVASNLGBcWc3LnpTpEnHu98C5IxotCILkBDQRYWT5HAQgAyv4RIYutp1xkdzRTWNsh8ATVgM9q0ly9/qICGWfpvYvH16athvWCxt+ZWxEIFeuD03sLpHf21CR1E6+RH2y3w7Hj9WJGBZuiVNrOZU8tqfvr2N6XR81+re+ajwC5OS9hz0M+G7SN6V/cP4rHnEHVSPqvimD2vM9ahd6cqM1TyBVrwMsXfNshlDlJo7XZR3IbRd1QJLtIND+6Dbi87w64xJU5JbqjOib9Uvt5tYwT735j39k52xEvIRMgkclENBvxdb+J9stXOl7jl0WEBZOslfsmwc9KsNtQeDpDIo5gcEZkKBLyJnG3zMPzy4uBa31wSNzDCef98ytSLuXwipfZqwARAQABiQElBBgBAgAPBQJYWT5HAhsMBQkDwmcAAAoJEHS/tgpIf57A5RoH/3Y8E1fdS5KMhom33XuR+hW/A4cCsNWk5Y9OrQ+p5Beegubk1QVn8/QWWwT4IbmcFrOv/KkfO39gamL4W6t2G4Se+Oww2aHIx6BkSOnoxORLh4b0/tMUEk6hv+XxnfCyBBN661EdWAZx0U61KTIoh5PAUUKEECgSOA/C/o8iC2RcQZ157sd0JVyT3QoHF4t24y9IpK7ktOm5xEz53PFc+HeTjcSjhQwD3BRQmyWgEHt+ET+FRvpJLdjx4A2VZXqLYKeQMfwwtyijjkGTHUf5OcPAyErkFR9qQUym2adQ4NLbsmNYcnFN5JNPkzqk48v3ueEMAMTBa7OneaGAJoQdhJk=","secret_shares": 1, "secret_threshold": 1, "pgp_keys": [ "mQENBFhZPkcBCADNApFjN/XvU/yeF4SRoHWzcEmummdMop6GiJg+ji//RPpCqzTY2ww3insb/2alLn7/V5LfuOIIfCFId76sWh0ckIXMdC9EOWlkmJi+Vlncq1Q/KRrE0WyUr8AaAFTbc51AAtUWWR9JW+0GwEpJxTkD9nwdU9Q5o+QKjj8BQ83UdzsnY8hUxSxnyiuufC+XWphUJLeXbJnKaaLs4gu/hoJ6SThEta2vg3B4nXGj3a3U3NuMnmzTlHbODB+bmhSjby68JKflgcQm8kpfxj/+56oX7fGn2xscWA8lBq3GkCFAqzf8j4S1+yJrLgI6//Qv1upYC9UbfYSkzhGPhOHvZL4BABEBAAG0QUtyenlzenRvZiBTemV3Y3p5ayAoRm9yIEhhc2hpb2NvcnAgVmF1bHQpIDxrLnN6ZXdjenlrQGthaW5vcy5jb20+iQE/BBMBAgApBQJYWT5HAhsDBQkDwmcABwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQdL+2Ckh/nsDrZgf/X4Rib24zkLd57TcaKa1/exbRXi5LvC9/EQKeBAr1+SjYqJptgxpZkjcLL3D3d7Uzj8PFHpDy4u8HSEunCG6WtOmeJcTocVIOB2sHor/4jGCazo/Q50mg4ui6totH55Jn0uCxjwB2Mv+ypbE6I9iI25srxkfo06t1tbPcGoGqxSvJdNSlemdmgOphjcIk5uuK5LWD8jbt6TYx66sb0Patl5i77pvuFrBnq8WWVNe1NUpO+oNggMfxaW2RMVYXJRC/S7eH6GIpsPo+h/S4V6037bfeVzUvRcYvdZvL3PQpI7QehweUw6I96SCVASNLGBcWc3LnpTpEnHu98C5IxotCILkBDQRYWT5HAQgAyv4RIYutp1xkdzRTWNsh8ATVgM9q0ly9/qICGWfpvYvH16athvWCxt+ZWxEIFeuD03sLpHf21CR1E6+RH2y3w7Hj9WJGBZuiVNrOZU8tqfvr2N6XR81+re+ajwC5OS9hz0M+G7SN6V/cP4rHnEHVSPqvimD2vM9ahd6cqM1TyBVrwMsXfNshlDlJo7XZR3IbRd1QJLtIND+6Dbi87w64xJU5JbqjOib9Uvt5tYwT735j39k52xEvIRMgkclENBvxdb+J9stXOl7jl0WEBZOslfsmwc9KsNtQeDpDIo5gcEZkKBLyJnG3zMPzy4uBa31wSNzDCef98ytSLuXwipfZqwARAQABiQElBBgBAgAPBQJYWT5HAhsMBQkDwmcAAAoJEHS/tgpIf57A5RoH/3Y8E1fdS5KMhom33XuR+hW/A4cCsNWk5Y9OrQ+p5Beegubk1QVn8/QWWwT4IbmcFrOv/KkfO39gamL4W6t2G4Se+Oww2aHIx6BkSOnoxORLh4b0/tMUEk6hv+XxnfCyBBN661EdWAZx0U61KTIoh5PAUUKEECgSOA/C/o8iC2RcQZ157sd0JVyT3QoHF4t24y9IpK7ktOm5xEz53PFc+HeTjcSjhQwD3BRQmyWgEHt+ET+FRvpJLdjx4A2VZXqLYKeQMfwwtyijjkGTHUf5OcPAyErkFR9qQUym2adQ4NLbsmNYcnFN5JNPkzqk48v3ueEMAMTBa7OneaGAJoQdhJk="] }' http://127.0.0.1:8200/v1/sys/init

Get list of Vault's backends

curl -H "X-Vault-Token: your_root_token" -X GET http://127.0.0.1:8200/v1/sys/mounts

Create backend named test

curl -H "X-Vault-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" -H "Content-Type: application/json" -X POST -d '{"type":"generic"}' http://127.0.0.1:8200/v1/sys/mounts/test

Get list of accessor tokens

curl -H "X-Vault-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" -X LIST http://127.0.0.1:8200/v1/auth/token/accessors

Get list of policies

curl -X GET http://127.0.0.1:8200/v1/sys/policy

Create container named "example" in secret backend and output all these key*, vaules* in the "example" container.

curl -H "X-Vault-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" -H "Content-Type: application/json" -X POST -d '{"key1":"value1", "key2": "value2"}' http://127.0.0.1:8200/v1/secret/example

Test

The tests directory contains tests for this role in the form of a Vagrant environment. After executing vagrant up in that directory, you should get an environment with one VM, attached to VirtualBox's default NAT network (Internet access is required to get vault package and dependencies).

The directory tests/roles/vault-provision is a symbolic link that should point to the root of this project in order to work.

The playbook test.yml applies the role to a VM, setting role variables.

vagrant provision should be running twice. First cycle is for initialization process. Then you have to unseal Vault. In second cycle you need to provide correct root token (decrypted by your private part of PGP or GPG key) in extra_vars.yml file.

Since now the box name is passed to Vagrantfile by parameter. You can test your changes on few different boxes by running for example:

vagrant --box=centos/6 up
vagrant --box=centos/7 up
vagrant --box=fedora/25-cloud-base up

If you skip box name default one will be used - centos/7.

Feedback, bug-reports, requests, ...

Issues, feature requests, ideas are appreciated and can be posted in the Issues section. Pull requests are also very welcome. Preferably, create a topic branch and when submitting, squash your commits into one (with a descriptive message).

Cheers !

License

MIT

Author Information

I attached links where you can find/get more information about me:

About

Ansible module for Hashicorp Vault provisioning

Install
ansible-galaxy install christophershoemaker/ansible-role-vault-provision
GitHub repository
License
Unknown
Downloads
53