eana / bitwarden-tf-aws

Terraform module for running a cheap and yet stable vaultwarden instance (formerly bitwarden_rs) in AWS
15 stars 1 forks source link
aws bitwarden terraform vaultwarden

bitwarden-tf-aws

Terraform module for deploying a cheap yet stable vaultwarden (formerly bitwarden_rs) to AWS.

Prerequisites

Features

How it works

This module provisions the following resources:

By default, an instance of the latest Amazon Linux 2 is launched. The instance will run init.sh to:

  1. Attach the ENI to eth1
  2. Attach the EBS volume as /dev/xvdf and mount it
  3. Install and configure docker, docker-compose, sops, fail2ban
  4. Start Bitwarden
  5. Switch the default route to eth1

Usage

Secrets

The secrets are encrypted and stored in the env.enc file. The file format is:

acme_email=email@example.com
signups_allowed=false
domain=bitwarden.example.com
smtp_host=smtp.gmail.com
smtp_port=587
smtp_ssl=true
smtp_username=username@gmail.com
smtp_password="V3ryStr0ngPa$sw0rd!"
enable_admin_page=true
admin_token=0YakKKYV01Qyz2Y3ynrJVYhw4fy1HtH+oCyVK8k3LhvnpawvkmUT/LZAibYJp3Eq
bucket=bitwarden-bucket
db_user=bitwarden
db_user_password=ChangeThisVeryStrongPassword
db_root_password=ReplaceThisEvenStrongerPassword

NOTE: I strongly advise NOT to enable the Admin Page, hence to remove the lines containing enable_admin_page and admin_token. If you still want to enable it, you should at least generate a 48 char long password.

$ openssl rand -base64 48

Once the env.enc file is populated with the correct secrets it must be encrypted. This file should never be left unencrypted.

$ SOPS_KMS_ARN="KMS_KEY_ARN" sops -e -i data/env.enc

replace KMS_KEY_ARN with the ARN of the KMS you want to use

Terraform

provider "aws" {
  region = "eu-west-1"
}

data "local_file" "this" {
  filename = "${path.module}/env.enc"
}

data "aws_kms_key" "this" {
  key_id = "alias/bitwarden-sops-encryption-key-prod"
}

module "bitwarden" {
  source         = "../"
  name           = "bitwarden"
  domain         = "bitwarden.example.org"
  environment    = "prod"
  route53_zone   = "example.org."
  ssh_cidr       = ["212.178.73.60/32"]
  env_file       = data.local_file.this.content
  instance_types = ["t2.micro", "t2.small", "t2.medium", "t2.large"]
}

TODO

  1. Add a restore script
  2. ~~Manage dependencies with renovate-bot~~
  3. Implement a retry mechanism when attaching ENI and EBS
  4. Detect if the EBS volume has been formatted or not
  5. Add logrotate for Traefik logs
  6. Catch the spot instance termination event and trigger a backup
  7. Verify that the application has properly launched by logging in as a dummy user

Contributions

This is an open source software. Feel free to open issues and pull requests.

Requirements

Name Version
terraform >= 0.13.1
aws >= 3.56.0
local >= 1.4

Providers

Name Version
aws >= 3.56.0

Modules

No modules.

Resources

Name Type
aws_autoscaling_group.this resource
aws_ebs_volume.this resource
aws_eip.this resource
aws_iam_instance_profile.this resource
aws_iam_role.this resource
aws_iam_role_policy.ebs resource
aws_iam_role_policy.eni resource
aws_iam_role_policy.s3 resource
aws_iam_role_policy.spot resource
aws_launch_template.this resource
aws_network_interface.this resource
aws_route53_record.this resource
aws_s3_bucket.bucket resource
aws_s3_bucket.resources resource
aws_s3_bucket_acl.bucket resource
aws_s3_bucket_acl.resources resource
aws_s3_bucket_lifecycle_configuration.bucket resource
aws_s3_bucket_policy.policy resource
aws_s3_bucket_public_access_block.bucket resource
aws_s3_bucket_public_access_block.resources resource
aws_s3_bucket_server_side_encryption_configuration.bucket resource
aws_s3_bucket_server_side_encryption_configuration.resources resource
aws_s3_bucket_versioning.bucket resource
aws_s3_bucket_versioning.resources resource
aws_s3_object.AWS_SpotInstancePricing resource
aws_s3_object.AWS_SpotTerminationNotifier resource
aws_s3_object.admin_fail2ban_filter resource
aws_s3_object.admin_fail2ban_jail resource
aws_s3_object.backup resource
aws_s3_object.bitwarden-logrotate resource
aws_s3_object.compose resource
aws_s3_object.env resource
aws_s3_object.fail2ban_filter resource
aws_s3_object.fail2ban_jail resource
aws_s3_object.restore resource
aws_s3_object.traefik-dynamic resource
aws_s3_object.traefik-logrotate resource
aws_security_group.this resource
aws_ami.this data source
aws_iam_policy_document.s3policy data source
aws_route53_zone.this data source
aws_subnets.this data source
aws_vpc.this data source

Inputs

Name Description Type Default Required
additional_tags Additional tags to apply to resources created with this module map(string) {} no
backup_schedule A cron expression to describe how often your data is backed up string "0 9 * * *" no
bucket_version_expiration_days Specifies when noncurrent object versions expire number 30 no
domain The domain name for the Bitwarden instance string n/a yes
env_file The name of the default docker-compose encrypted env file string n/a yes
environment The environment to deploy to string n/a yes
instance_types Instance types in the Launch Template. The first instance in the list will have the list(string)
[
"t2.micro",
"t2.small"
]
no
name Name to be used as identifier string "bitwarden" no
route53_zone The zone in which the DNS record will be created string n/a yes
ssh_cidr The IP ranges from where the SSH connections will be allowed list(any) [] no
tags Tags applied to resources created with this module map(any) {} no

Outputs

Name Description
iam_role_name The IAM role for the Bitwarden Instance
public_ip The public IP address the Bitwarden instance will have
s3_bucket The S3 bucket where the backups will be stored
s3_resources The S3 bucket where all the resource files will be stored
sg_id ID of the security group
url The URL where the Bitwarden Instance can be accessed
volume_id The volume ID