PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/infrastructures/terraform/aws/data/vault/main.tf

https://gitlab.com/OBSERVER-DLL/atlas-examples
Terraform | 309 lines | 238 code | 54 blank | 17 comment | 19 complexity | a2a3b976a9804dd644f619fd3731d53f MD5 | raw file
  1. variable "name" { default = "vault" }
  2. variable "vpc_id" {}
  3. variable "vpc_cidr" {}
  4. variable "azs" {}
  5. variable "private_subnet_ids" {}
  6. variable "public_subnet_ids" {}
  7. variable "count" {}
  8. variable "instance_type" {}
  9. variable "amis" {}
  10. variable "ssl_cert_name" {}
  11. variable "ssl_cert_crt" {}
  12. variable "ssl_cert_key" {}
  13. variable "key_name" {}
  14. variable "key_path" {}
  15. variable "bastion_host" {}
  16. variable "bastion_user" {}
  17. variable "user_data" {}
  18. variable "atlas_username" {}
  19. variable "atlas_environment" {}
  20. variable "atlas_token" {}
  21. variable "consul_ips" {}
  22. resource "aws_security_group" "vault" {
  23. name = "${var.name}"
  24. vpc_id = "${var.vpc_id}"
  25. description = "Security group for Vault"
  26. tags { Name = "${var.name}" }
  27. ingress {
  28. protocol = -1
  29. from_port = 0
  30. to_port = 0
  31. cidr_blocks = ["${var.vpc_cidr}"]
  32. }
  33. egress {
  34. protocol = -1
  35. from_port = 0
  36. to_port = 0
  37. cidr_blocks = ["0.0.0.0/0"]
  38. }
  39. }
  40. resource "template_file" "user_data" {
  41. filename = "${var.user_data}"
  42. count = "${var.count}"
  43. vars {
  44. atlas_username = "${var.atlas_username}"
  45. atlas_environment = "${var.atlas_environment}"
  46. atlas_token = "${var.atlas_token}"
  47. service = "${var.name}"
  48. node_name = "${var.name}.${count.index+1}"
  49. cert_name = "${var.ssl_cert_name}"
  50. }
  51. }
  52. resource "aws_instance" "vault" {
  53. ami = "${element(split(",", var.amis), count.index)}"
  54. count = "${var.count}"
  55. instance_type = "${var.instance_type}"
  56. key_name = "${var.key_name}"
  57. subnet_id = "${element(split(",", var.private_subnet_ids), count.index)}"
  58. user_data = "${element(template_file.user_data.*.rendered, count.index)}"
  59. vpc_security_group_ids = ["${aws_security_group.vault.id}"]
  60. tags { Name = "${var.name}.${count.index+1}" }
  61. }
  62. resource "null_resource" "vault_init" {
  63. provisioner "remote-exec" {
  64. connection {
  65. user = "ubuntu"
  66. host = "${element(aws_instance.vault.*.private_ip, 0)}"
  67. key_file = "${var.key_path}"
  68. bastion_host = "${var.bastion_host}"
  69. bastion_user = "${var.bastion_user}"
  70. }
  71. inline = [ <<COMMANDS
  72. #!/bin/bash
  73. set -e
  74. # Join Consul cluster
  75. consul join ${replace(var.consul_ips, ",", " ")}
  76. # Remote commands utilize Consul's KV store, wait until ready
  77. SLEEPTIME=1
  78. cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/consul/ready?raw"; }
  79. # Wait for the Consul cluster to become ready
  80. while ! cget | grep "true"; do
  81. if [ $SLEEPTIME -gt 24 ]; then
  82. echo "ERROR: CONSUL DID NOT COMPLETE SETUP! Manual intervention required."
  83. exit 2
  84. else
  85. echo "Blocking until Consul is ready, waiting $SLEEPTIME second(s)..."
  86. sleep $SLEEPTIME
  87. ((SLEEPTIME+=1))
  88. fi
  89. done
  90. cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
  91. if [ ! $(cget root-token) ]; then
  92. echo "Initialize Vault"
  93. vault init | tee /tmp/vault.init > /dev/null
  94. # Store master keys in consul for operator to retrieve and remove
  95. i=1
  96. cat /tmp/vault.init | grep '^Key' | awk '{print $3}' | for key in $(cat -); do
  97. curl -fX PUT 127.0.0.1:8500/v1/kv/service/vault/unseal-key-$i -d $key
  98. ((i = i + 1))
  99. done
  100. export ROOT_TOKEN=$(cat /tmp/vault.init | grep '^Initial' | awk '{print $4}')
  101. curl -fX PUT 127.0.0.1:8500/v1/kv/service/vault/root-token -d $ROOT_TOKEN
  102. # Remove master keys from disk
  103. shred /tmp/vault.init
  104. else
  105. echo "Vault has already been initialized, skipping"
  106. fi
  107. COMMANDS ]
  108. }
  109. }
  110. resource "null_resource" "vault_unseal" {
  111. count = "${var.count}"
  112. depends_on = ["null_resource.vault_init"]
  113. provisioner "remote-exec" {
  114. connection {
  115. user = "ubuntu"
  116. host = "${element(aws_instance.vault.*.private_ip, count.index)}"
  117. key_file = "${var.key_path}"
  118. bastion_host = "${var.bastion_host}"
  119. bastion_user = "${var.bastion_user}"
  120. }
  121. inline = [ <<COMMANDS
  122. #!/bin/bash
  123. set -e
  124. # Join Consul cluster
  125. consul join ${replace(var.consul_ips, ",", " ")}
  126. # Remote commands utilize Consul's KV store, wait until ready
  127. SLEEPTIME=1
  128. cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/consul/ready?raw"; }
  129. # Wait for the Consul cluster to become ready
  130. while ! cget | grep "true"; do
  131. if [ $SLEEPTIME -gt 24 ]; then
  132. echo "ERROR: CONSUL DID NOT COMPLETE SETUP! Manual intervention required."
  133. exit 2
  134. else
  135. echo "Blocking until Consul is ready, waiting $SLEEPTIME second(s)..."
  136. sleep $SLEEPTIME
  137. ((SLEEPTIME+=1))
  138. fi
  139. done
  140. cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
  141. echo "Unsealing Vault"
  142. vault unseal $(cget unseal-key-1)
  143. vault unseal $(cget unseal-key-2)
  144. vault unseal $(cget unseal-key-3)
  145. COMMANDS ]
  146. }
  147. }
  148. resource "null_resource" "vault_mount_transit" {
  149. count = "${var.count}"
  150. depends_on = ["null_resource.vault_unseal"]
  151. provisioner "remote-exec" {
  152. connection {
  153. user = "ubuntu"
  154. host = "${element(aws_instance.vault.*.private_ip, count.index)}"
  155. key_file = "${var.key_path}"
  156. bastion_host = "${var.bastion_host}"
  157. bastion_user = "${var.bastion_user}"
  158. }
  159. inline = [ <<COMMANDS
  160. #!/bin/bash
  161. set -e
  162. cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
  163. if vault status | grep standby > /dev/null; then
  164. echo "Mounts only run on the leader. Exiting."
  165. exit 0
  166. fi
  167. cget root-token | vault auth -
  168. vault mount transit
  169. shred -u -z ~/.vault-token
  170. # Report that vault is ready to use. This is used over in app setup to
  171. # wait for vault to be ready before inserting the vault policy.
  172. curl -XPUT http://127.0.0.1:8500/v1/kv/service/vault/ready -d true
  173. COMMANDS ]
  174. }
  175. }
  176. resource "aws_security_group" "elb" {
  177. name = "${var.name}-elb"
  178. vpc_id = "${var.vpc_id}"
  179. description = "Security group for Vault ELB"
  180. tags { Name = "${var.name}-elb" }
  181. ingress {
  182. protocol = "tcp"
  183. from_port = 80
  184. to_port = 80
  185. cidr_blocks = ["${var.vpc_cidr}"]
  186. }
  187. ingress {
  188. protocol = "tcp"
  189. from_port = 443
  190. to_port = 443
  191. cidr_blocks = ["${var.vpc_cidr}"]
  192. }
  193. egress {
  194. protocol = -1
  195. from_port = 0
  196. to_port = 0
  197. cidr_blocks = ["0.0.0.0/0"]
  198. }
  199. }
  200. resource "aws_iam_server_certificate" "vault" {
  201. name = "${var.name}"
  202. certificate_body = "${file("${var.ssl_cert_crt}")}"
  203. private_key = "${file("${var.ssl_cert_key}")}"
  204. provisioner "local-exec" {
  205. command = <<EOF
  206. echo "Sleep 10 secends so that mycert is propagated by aws iam service"
  207. echo "See https://github.com/hashicorp/terraform/issues/2499 (terraform ~v0.6.1)"
  208. sleep 10
  209. EOF
  210. }
  211. }
  212. resource "aws_elb" "vault" {
  213. name = "${var.name}"
  214. connection_draining = true
  215. connection_draining_timeout = 400
  216. internal = true
  217. subnets = ["${split(",", var.public_subnet_ids)}"]
  218. security_groups = ["${aws_security_group.elb.id}"]
  219. instances = ["${aws_instance.vault.*.id}"]
  220. listener {
  221. lb_port = 80
  222. lb_protocol = "tcp"
  223. instance_port = 8200
  224. instance_protocol = "tcp"
  225. }
  226. listener {
  227. lb_port = 443
  228. lb_protocol = "tcp"
  229. instance_port = 8200
  230. instance_protocol = "tcp"
  231. # There is a bug with setting ssl_certificate_id right now. When it's not set,
  232. # you will see TLS warnings every 5 minutes in the Vault logs due to the load
  233. # balancer not using the proper version of TLS when doing health checks.
  234. # ssl_certificate_id = "${aws_iam_server_certificate.vault.arn}"
  235. }
  236. health_check {
  237. healthy_threshold = 2
  238. unhealthy_threshold = 3
  239. timeout = 5
  240. interval = 15
  241. target = "HTTPS:8200/v1/sys/health"
  242. }
  243. }
  244. output "dns_name" { value = "${aws_elb.vault.dns_name}" }
  245. output "private_ips" { value = "${join(",", aws_instance.vault.*.private_ip)}" }
  246. output "instructions" {
  247. value = <<EOF
  248. We use an instance of HashiCorp Vault for secrets management.
  249. It has been automatically initialized and unsealed once. Future unsealing must
  250. be done manually.
  251. The unseal keys and root token have been temporarily stored in Consul K/V.
  252. /service/vault/root-token
  253. /service/vault/unseal-key-{1..5}
  254. Please securely distribute and record these secrets and remove them from Consul.
  255. EOF }