
In our tutorial, we will be using embedded integrated storage.

# Vault cluster
resource "digitalocean_droplet" "vault-nl-1" {
  image          	= var.ol7_base_image
  name           	= "vault-nl-1.example.com"
  region         	= "ams3"
  size           	= var.size
  tags           	= ["vault"]
  monitoring   	= true
}
resource "digitalocean_droplet" "vault-de-1" {
  image          	= var.ol7_base_image
  name           	= "vault-de-1.example.com"
  region         	= "fra1"
  size           	= var.size
  tags           	= ["vault"]
  monitoring    	= true
}
resource "digitalocean_droplet" "vault-uk-1" {
  image          	= var.ol7_base_image
  name           	= "vault-uk-1.example.com"
  region         	= "lon1"
  size           	= var.size
  tags           	= ["vault"]
  monitoring    	= true
}
variable "size" {
  description = "Droplet size"
  default 	= "s-1vcpu-1gb"
}
variable "ol7_base_image" {
  description = "Base ol7 DO image made by packer"
  default 	= 312166483
  type = number
}
resource "digitalocean_firewall" "general-firewall" {
  name = "general-firewall"
  tags = [ "vault" ]
 inbound_rule {
	protocol     	= "icmp"
	source_addresses = ["0.0.0.0/0", "::/0"]
  }
  inbound_rule {
	protocol   = "tcp"
	port_range = "22"
	source_addresses = var.bastion_ip_add
  }
  outbound_rule {
	protocol          	= "udp"
	port_range        	= "all"
	destination_addresses = ["0.0.0.0/0", "::/0"]
  }
  outbound_rule {
	protocol          	= "icmp"
	destination_addresses = ["0.0.0.0/0", "::/0"]
  }
  outbound_rule {
	protocol          	= "tcp"
	port_range        	= "all"
	destination_addresses = ["0.0.0.0/0", "::/0"]
  }
}
variable "bastion_ip_add" {
  description = "List of bastion IP addresses"
  default 	= ["144.85.22.183/32",
               "12.68.22.226/32",
            	]
}
variable "internal_vpn_ip_add" {
  description = "List of internal VPN IP addresses"
  default 	= ["122.85.77.183/32",
               "44.68.2.226/32",
            	]
}
variable "customer_customer_1_ip_add" {
  description = "List of customer_1 IP addresses"
  default 	= ["158.63.250.15/32",
               "158.63.250.16/32",
            	]
}
  inbound_rule {
	protocol   = "tcp"
	port_range = "8200"
	source_addresses = setunion(var.internal_vpn_ip_add, var.bastion_ip_add, var.customer_customer_1_ip_add)
  }
terraform init
terraform plan
terraform apply
- name: Prepare certificates
  hosts: hashicorp_vault
  gather_facts: true
  become: yes
  roles:
	- role: letsencrypt-ssl
  	tags: letsencrypt
  post_tasks:
	- name: Copy the certificates to the vault config dir for the first time
  	shell: |
    	rsync -L /etc/letsencrypt/live/{{ inventory_hostname }}/privkey.pem /etc/vault.d/privkey.pem
    	rsync -L /etc/letsencrypt/live/{{ inventory_hostname }}/fullchain.pem /etc/vault.d/fullchain.pem
    	chown vault:vault /etc/vault.d/privkey.pem
    	chown vault:vault /etc/vault.d/fullchain.pem
    	pkill -SIGHUP vault
  	args:
    	creates: /etc/vault.d/fullchain.pem
  	tags: letsencrypt
- name: Deploy hashicorp vault cluster
  hosts: hashicorp_vault
  gather_facts: true
  become: yes
  roles:
	- role: ansible-community.ansible-vault
  	tags: vault_install
vault_version: "1.12.0"
vault_install_hashi_repo: true
vault_harden_file_perms: true
vault_service_restart: false
# listeners configuration
vault_api_addr: "{{ vault_protocol }}://{{ inventory_hostname }}:{{ vault_port }}"
vault_tls_disable: false
vault_tls_certs_path: /etc/vault.d
vault_tls_private_path: /etc/vault.d
vault_tls_cert_file: fullchain.pem
vault_tls_key_file: privkey.pem
vault_tls_min_version: "tls12"
vault_raft_cluster_members:
  - peer: hasd-vault-nl-1.itsts.net
	api_addr: https://vault-nl-1.example.com:8200
  - peer: hasd-vault-de-1.itsts.net
	api_addr: https://vault-de-1.example.com:8200
  - peer: hasd-vault-uk-1.itsts.net
	api_addr: https://vault-uk-1.example.com:8200
# Ansible managed
cluster_name = "dc1"
max_lease_ttl = "768h"
default_lease_ttl = "768h"
disable_clustering = "False"
cluster_addr = "https://333.222.10.107:8201"
api_addr = "https://vault-nl-1.example.com:8200"
plugin_directory = "/usr/local/lib/vault/plugins"
listener "tcp" {
  address = "333.222.10.107:8200"
  cluster_address = "333.222.10.107:8201"
  tls_cert_file = "/etc/vault.d/fullchain.pem"
  tls_key_file = "/etc/vault.d/privkey.pem"
  tls_min_version  = "tls12"
  tls_disable = "false"
  }
listener "tcp" {
  address = "127.0.0.1:8200"
  cluster_address = "333.222.10.107:8201"
  tls_cert_file = "/etc/vault.d/fullchain.pem"
  tls_key_file = "/etc/vault.d/privkey.pem"
  tls_min_version  = "tls12"
  tls_disable = "false"
  }
storage "raft" {
  path = "/opt/vault/data"
  node_id = "hasd-vault-nl-1"
  retry_join {
	leader_api_addr =  "https://vault-de-1.example.com:8200"
  }
  retry_join {
	leader_api_addr =  "https://vault-uk-1.example.com:8200"
  }
    	}
// HashiCorp recommends disabling mlock when using Raft.
disable_mlock = true
ui = true
Be extremely careful at this stage, it is vitally important!
Lost Shamir keys = permanently locked storage after a daemon restart.
rsync -L /etc/letsencrypt/live/{{ inventory_hostname }}/privkey.pem /etc/vault.d/privkey.pem
rsync -L /etc/letsencrypt/live/{{ inventory_hostname }}/fullchain.pem /etc/vault.d/fullchain.pem
chown vault:vault /etc/vault.d/privkey.pem
chown vault:vault /etc/vault.d/fullchain.pem
pkill -SIGHUP vault
#!/bin/bash
LEADER=$(vault status -format=json | jq -r '.leader_address')
HOSTNAME=$(hostname)
ROLE_ID_VAULT_MAINTENANCE={{ vault_maintenance_role_id }}
# Get the secret ID for the vault_maintenance_snapshot AppRole
SECRET_ID_VAULT_MAINTENANCE=$(cat /root/approle_vault_maintenance_snapshot_secret_id)
# Check if this node is the leader and if the hostname matches
if [[ "$LEADER" == "https://$HOSTNAME:8200" ]]; then
  TOKEN=$(vault write auth/approle/login --format=json role_id=$ROLE_ID_VAULT_MAINTENANCE secret_id="$SECRET_ID_VAULT_MAINTENANCE" | jq -r '.auth.client_token')
  vault login $TOKEN >/dev/null 2>&1
  vault operator raft snapshot save {{ vault_snapshot_location }}
  # Send the result to the cloud backup. This will happen on the leader node only
  /root/scripts/duplicity-backup.sh -c /root/scripts/{{ duplicity_config_name_s3 }}.conf -b > /dev/null
fi
path "sys/storage/raft/snapshot"
{
  capabilities = ["read", "update"]
}
path "auth/token/revoke"
{
  capabilities = ["update"]
}
