bitwarden deployment

This commit is contained in:
Julian Tölle 2019-01-30 19:49:47 +01:00
commit 42ec743a00
24 changed files with 498 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
keys/id_terraform*
credentials.tfvars
terraform.tfstate*
.terraform

25
Makefile Normal file
View file

@ -0,0 +1,25 @@
TF=terraform
TFFLAGS=-var-file=credentials.tfvars
VALIDATE=terraform validate -check-variables=false
apply: init
$(TF) apply $(TFFLAGS)
plan: init
$(TF) plan $(TFFLAGS)
destroy: init
$(TF) destroy $(TFFLAGS)
lint: init
$(VALIDATE) modules/docker_node
$(VALIDATE) modules/floating_ip
$(VALIDATE) services/bitwarden
$(VALIDATE) .
init: keys
$(TF) init
keys: keys/id_terraform
echo "No private key found! Generating Terraform SSH Keys."
./bootstrap-keys.sh

2
bootstrap-keys.sh Executable file
View file

@ -0,0 +1,2 @@
ssh-keygen -t rsa -C "terraform@narando.de" -f keys/id_terraform
chmod 600 keys/id_terraform*

1
keys/README Executable file
View file

@ -0,0 +1 @@
Please execute ./bootstrap-keys.sh to generate TLS key for Terraform.

11
main.tf Executable file
View file

@ -0,0 +1,11 @@
module bitwarden {
source = "services/bitwarden"
location = "${var.hcloud_location}"
ssh_key_id = "${hcloud_ssh_key.terraform.id}"
bitwarden_admin_email = "${var.admin_email}"
}
variable admin_email {
type = "string"
}

20
modules/docker_node/main.tf Executable file
View file

@ -0,0 +1,20 @@
resource "hcloud_server" "node" {
name = "${var.name}"
image = "${var.image}"
server_type = "${var.server_type}"
location = "${var.location}"
ssh_keys = ["${var.ssh_key_id}"]
connection {
private_key = "${file("./keys/id_terraform")}"
}
provisioner "remote-exec" {
scripts = [
"modules/docker_node/scripts/wait-cloud-init.sh",
"modules/docker_node/scripts/install-docker.sh",
"modules/docker_node/scripts/install-docker-compose.sh",
]
}
}

7
modules/docker_node/outputs.tf Executable file
View file

@ -0,0 +1,7 @@
output ip {
value = "${hcloud_server.node.ipv4_address}"
}
output id {
value = "${hcloud_server.node.id}"
}

View file

@ -0,0 +1,3 @@
curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

View file

@ -0,0 +1,28 @@
#!/bin/bash
set -e
# Source: https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository
echo "# apt-get update"
apt-get update
echo "# apt-get upgrade -y"
DEBIAN_FRONTEND='noninteractive' apt-get -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' upgrade
# Add Repository
echo "# apt-get install"
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
echo "# apt-get update"
apt-get update
# Install Docker
echo "# apt-get install docker-ce"
apt-get install -y docker-ce

View file

@ -0,0 +1,13 @@
# cloud-init is running at boot time and blocking access to apt.
# Before doing anything we should wait for it to finish.
# cloud-init creates a file after finishing boot.
echo "Waiting for cloud-init to finish provisioning the instance."
while [ ! -f /var/lib/cloud/instance/boot-finished ]
do
echo "#"
sleep 2
done
# Wait some more to be sure
sleep 10

22
modules/docker_node/vars.tf Executable file
View file

@ -0,0 +1,22 @@
variable name {
type = "string"
}
variable image {
type = "string"
default = "ubuntu-18.04"
}
variable server_type {
type = "string"
default = "cx11"
}
variable location {
type = "string"
default = "nbg1"
}
variable ssh_key_id {
type = "string"
}

View file

@ -0,0 +1,4 @@
auto eth0:1
iface eth0:1 inet static
address ${FLOATING_IP}
netmask 255.255.255.255

48
modules/floating_ip/main.tf Executable file
View file

@ -0,0 +1,48 @@
#################
### IP ADDRESS ##
#################
resource hcloud_floating_ip main {
type = "${var.type}"
description = "${var.host}"
home_location = "${var.location}"
}
resource "hcloud_rdns" "main" {
floating_ip_id = "${hcloud_floating_ip.main.id}"
ip_address = "${hcloud_floating_ip.main.ip_address}"
dns_ptr = "${var.host}"
}
###################################
### ASSIGNMENT AND PROVISIONING ###
###################################
data "template_file" "network_config" {
template = "${file("modules/floating_ip/files/99-floating.cfg")}"
vars {
FLOATING_IP = "${hcloud_floating_ip.main.ip_address}"
}
}
resource hcloud_floating_ip_assignment main {
floating_ip_id = "${hcloud_floating_ip.main.id}"
server_id = "${var.server_id}"
connection = {
host = "${var.server_ip}"
private_key = "${file("keys/id_terraform")}"
}
provisioner file {
content = "${data.template_file.network_config.rendered}"
destination = "/etc/network/interfaces.d/99-floating.cfg"
}
provisioner remote-exec {
inline = [
"ifdown eth0:1 ; ifup eth0:1",
]
}
}

3
modules/floating_ip/outputs.tf Executable file
View file

@ -0,0 +1,3 @@
output ip {
value = "${hcloud_floating_ip.main.ip_address}"
}

21
modules/floating_ip/vars.tf Executable file
View file

@ -0,0 +1,21 @@
variable host {
type = "string"
}
variable type {
type = "string"
default = "ipv4"
}
variable server_id {
type = "string"
}
variable server_ip {
type = "string"
}
variable location {
type = "string"
default = "nbg1"
}

3
output.tf Executable file
View file

@ -0,0 +1,3 @@
output bitwarden_ip {
value = "${module.bitwarden.ip}"
}

25
provider_hcloud.tf Executable file
View file

@ -0,0 +1,25 @@
# Set the variable value in *.tfvars file
# or using -var="hcloud_token=..." CLI option
variable "hcloud_token" {}
variable "hcloud_location" {}
# Configure the Hetzner Cloud Provider
provider "hcloud" {
version = "~> 1.7.0"
token = "${var.hcloud_token}"
}
#######################
## Terraform SSH Key ##
#######################
resource "hcloud_ssh_key" "terraform" {
name = "terraform"
public_key = "${file("./keys/id_terraform.pub")}"
labels = {
"description" = "Used by terraform to provision nodes"
}
}

7
provider_other.tf Executable file
View file

@ -0,0 +1,7 @@
provider "null" {
version = "~> 1.0"
}
provider "template" {
version = "~> 1.0"
}

View file

@ -0,0 +1,46 @@
version: "2.1"
services:
traefik:
image: traefik:1.7
restart: always
ports:
- 80:80
- 443:443
networks:
- web
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${INSTALL_DIR}/traefik.toml:/traefik.toml
- ${INSTALL_DIR}/acme.json:/acme.json
container_name: traefik
bitwarden:
image: mprasil/bitwarden:latest
restart: always
expose:
- "80"
- "3012"
networks:
- web
volumes:
- ${BITWARDEN_DATA_DIR}/:/data/
environment:
SIGNUPS_ALLOWED: "false"
SERVER_ADMIN_EMAIL: "${BITWARDEN_ADMIN_EMAIL}"
labels:
- "traefik.frontend.rule=Host:${HOST}"
- "traefik.docker.network=web"
- "traefik.port=80"
- "traefik.enable=true"
- "traefik.web.frontend.rule=Host:${HOST}"
- "traefik.web.port=80"
- "traefik.hub.frontend.rule=Path:/notifications/hub"
- "traefik.hub.port=3012"
- "traefik.negotiate.frontend.rule=Path:/notifications/hub/negotiate"
- "traefik.negotiate.port=80"
container_name: bitwarden
networks:
web:
name: web

View file

@ -0,0 +1,28 @@
debug = true
logLevel = "INFO"
defaultEntryPoints = ["https","http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[retry]
[docker]
endpoint = "unix:///var/run/docker.sock"
watch = true
exposedByDefault = false
[acme]
email = "julian.toelle97@gmail.com"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"

134
services/bitwarden/main.tf Executable file
View file

@ -0,0 +1,134 @@
##########
## NODE ##
##########
module "node" {
source = "../../modules/docker_node"
name = "${var.name}"
ssh_key_id = "${var.ssh_key_id}"
}
############
## VOLUME ##
############
resource "hcloud_volume" "data" {
name = "${var.volume_name}"
size = "${var.volume_size}"
location = "${var.location}"
format = "ext4"
}
resource hcloud_volume_attachment "data" {
volume_id = "${hcloud_volume.data.id}"
server_id = "${module.node.id}"
automount = true
}
resource null_resource "start-stop-bitwarden" {
# This resource is responsible for starting and stopping Bitwarden before
# changing volume assignments. This should avoid data corruption.
depends_on = ["hcloud_volume_attachment.data", "null_resource.install-bitwarden"]
triggers = {
id = "${hcloud_volume_attachment.data.id}"
}
connection = {
host = "${module.node.ip}"
private_key = "${file("keys/id_terraform")}"
}
provisioner remote-exec {
# Stop bitwarden container before unmounting data volume
when = "destroy"
inline = [
"echo Stopping Bitwarden",
"docker stop bitwarden",
]
}
provisioner remote-exec {
# Start bitwarden after mounting new volume
inline = [
"echo Starting Bitwarden",
"cd ${local.install_dir}",
"docker-compose up -d",
]
}
}
################
## IP ADDRESS ##
################
module floating_ip {
source = "../../modules/floating_ip"
location = "${var.location}"
host = "${var.host}"
server_id = "${module.node.id}"
server_ip = "${module.node.ip}"
}
#################
## APPLICATION ##
#################
data "template_file" "compose" {
template = "${file("services/bitwarden/files/docker-compose.yaml")}"
vars = {
INSTALL_DIR = "${local.install_dir}"
BITWARDEN_DATA_DIR = "${local.bitwarden_data_dir}"
BITWARDEN_ADMIN_EMAIL = "${var.bitwarden_admin_email}"
HOST = "${var.host}"
}
}
resource "null_resource" "install-bitwarden" {
depends_on = ["module.node", "hcloud_volume_attachment.data"]
triggers {
node_id = "${module.node.id}"
volume_id = "${hcloud_volume.data.id}"
docker_compose = "${sha1(data.template_file.compose.rendered)}"
traefik_config = "${sha1(file("services/bitwarden/files/traefik.toml"))}"
}
connection = {
host = "${module.node.ip}"
private_key = "${file("keys/id_terraform")}"
}
provisioner remote-exec {
inline = [
"mkdir -p ${local.install_dir}",
"touch ${local.install_dir}/acme.json",
"chmod 600 ${local.install_dir}/acme.json",
]
}
provisioner file {
content = "${data.template_file.compose.rendered}"
destination = "${local.install_dir}/docker-compose.yaml"
}
provisioner file {
source = "services/bitwarden/files/traefik.toml"
destination = "${local.install_dir}/traefik.toml"
}
provisioner remote-exec {
inline = [
"cd ${local.install_dir}",
"docker-compose pull",
"docker-compose up -d",
]
}
}

3
services/bitwarden/output.tf Executable file
View file

@ -0,0 +1,3 @@
output ip {
value = "${module.floating_ip.ip}"
}

39
services/bitwarden/vars.tf Executable file
View file

@ -0,0 +1,39 @@
variable location {
type = "string"
default = "nbg1"
}
variable ssh_key_id {
type = "string"
}
variable volume_size {
type = "string"
default = 10
}
variable name {
type = "string"
default = "bitwarden"
}
variable volume_name {
type = "string"
default = "bitwarden-data"
}
variable host {
type = "string"
default = "bitwarden.apricote.de"
}
variable bitwarden_admin_email {
type = "string"
}
locals = {
volume_path = "/mnt/${var.volume_name}"
install_dir = "/opt/${var.name}"
bitwarden_data_dir = "${local.volume_path}"
}

1
terraform.tfvars Executable file
View file

@ -0,0 +1 @@
hcloud_location = "nbg1"