Passbolt Server Automated Setup

Setup

Passbolt is a password manager that can be self hosted. This post describes how to automatically deploy passbolt on DigitalOcean. I wrote the code to do this here. After you clone the code, you need both terraform and ansible to run the makefile. You will be charged for what you use on DigitalOcean. I am not responsible for any charges you incurr.

Customize Secrets

There are a few secrets in the group vars that need to be updated. In the repo open the file ansible/group_vars/passbolt.yml. The three that need to be updated are user_email, user_fname, and user_lname. Make sure to update them to the values you need. If you need to use vault to encrypt the secrets try the following:

echo -n "yourvaluehere" | ansible-vault encrypt_string

Deploy Passbolt

In the root of the code repo, run a make command to build/deploy the application.

dan@ubuntu:~/git/digitalocean-passbolt$ make build
cd terraform && terraform init && terraform apply

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of digitalocean/digitalocean from the dependency lock file
- Using previously-installed digitalocean/digitalocean v2.19.0

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.passbolt will be created
  + resource "digitalocean_droplet" "passbolt" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + graceful_shutdown    = false
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "passbolt01"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "nyc3"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + ssh_keys             = [
          + "32690924",
          + "32843241",
        ]
      + status               = (known after apply)
      + urn                  = (known after apply)
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

  # digitalocean_firewall.web will be created
  + resource "digitalocean_firewall" "web" {
      + created_at      = (known after apply)
      + droplet_ids     = (known after apply)
      + id              = (known after apply)
      + name            = "passbolt-firewall"
      + pending_changes = (known after apply)
      + status          = (known after apply)

      + inbound_rule {
          + port_range                = "22"
          + protocol                  = "tcp"
          + source_addresses          = [
              + "0.0.0.0/0",
              + "::/0",
            ]
          + source_droplet_ids        = []
          + source_kubernetes_ids     = []
          + source_load_balancer_uids = []
          + source_tags               = []
        }
      + inbound_rule {
          + port_range                = "443"
          + protocol                  = "tcp"
          + source_addresses          = [
              + "0.0.0.0/0",
              + "::/0",
            ]
          + source_droplet_ids        = []
          + source_kubernetes_ids     = []
          + source_load_balancer_uids = []
          + source_tags               = []
        }

      + outbound_rule {
          + destination_addresses          = [
              + "0.0.0.0/0",
              + "::/0",
            ]
          + destination_droplet_ids        = []
          + destination_kubernetes_ids     = []
          + destination_load_balancer_uids = []
          + destination_tags               = []
          + port_range                     = "443"
          + protocol                       = "tcp"
        }
      + outbound_rule {
          + destination_addresses          = [
              + "0.0.0.0/0",
              + "::/0",
            ]
          + destination_droplet_ids        = []
          + destination_kubernetes_ids     = []
          + destination_load_balancer_uids = []
          + destination_tags               = []
          + port_range                     = "53"
          + protocol                       = "tcp"
        }
      + outbound_rule {
          + destination_addresses          = [
              + "0.0.0.0/0",
              + "::/0",
            ]
          + destination_droplet_ids        = []
          + destination_kubernetes_ids     = []
          + destination_load_balancer_uids = []
          + destination_tags               = []
          + port_range                     = "80"
          + protocol                       = "tcp"
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + dev_instance_ip_addr = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

digitalocean_droplet.passbolt: Creating...
digitalocean_droplet.passbolt: Still creating... [10s elapsed]
digitalocean_droplet.passbolt: Still creating... [20s elapsed]
digitalocean_droplet.passbolt: Still creating... [30s elapsed]
digitalocean_droplet.passbolt: Still creating... [40s elapsed]
digitalocean_droplet.passbolt: Still creating... [50s elapsed]
digitalocean_droplet.passbolt: Creation complete after 52s [id=304476308]
digitalocean_firewall.web: Creating...
digitalocean_firewall.web: Creation complete after 1s [id=6e1db47d-f277-45ea-84da-a546e29c00f4]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

dev_instance_ip_addr = "104.131.78.236"
bash update-ansiblehosts.sh
sleep 60
cd ansible && ansible-playbook -i ansible_hosts_automated playbooks/passbolt.yml --ask-vault-password
Vault password: 

PLAY [passbolt] ****************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************
The authenticity of host '104.131.78.236 (104.131.78.236)' can't be established.
ED25519 key fingerprint is SHA256:LA+GfgLXilWdZd7G1okZT7FKeYLogPbOt1XQWI+RiOg.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
ok: [104.131.78.236]

TASK [passbolt : generate certs] ***********************************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : install docker] ***********************************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : template docker-compose file] *********************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : run compose file] *********************************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : wait 20 seconds for sql to start] *****************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : create first user] ********************************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : pull ssl cert out of container] *******************************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : pull ssl cert to local desktop for distribution] **************************************************************************************************************************************
changed: [104.131.78.236]

TASK [passbolt : output admin join url] ****************************************************************************************************************************************************************
ok: [104.131.78.236] => {
    "msg": {
        "changed": true,
        "cmd": [
            "docker-compose",
            "exec",
            "passbolt",
            "su",
            "-m",
            "-c",
            "/usr/share/php/passbolt/bin/cake passbolt register_user -u ******************************************",
            "-s",
            "/bin/sh",
            "www-data"
        ],
        "delta": "0:00:03.608413",
        "end": "2022-06-16 12:05:33.265691",
        "failed": false,
        "rc": 0,
        "start": "2022-06-16 12:05:29.657278",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "\r\n     ____                  __          ____  \r\n    / __ \\____  _____ ____/ /_  ____  / / /_ \r\n   / /_/ / __ `/ ___/ ___/ __ \\/ __ \\/ / __/ \r\n  / ____/ /_/ (__  |__  ) /_/ / /_/ / / /    \r\n /_/    \\__,_/____/____/_.___/\\____/_/\\__/   \r\n\r\n Open source password manager for teams\r\n-------------------------------------------------------------------------------\r\n\u001b[32mUser saved successfully.\u001b[0m\r\n\u001b[32mTo start registration follow the link provided in your mailbox or here: \r\nhttps://104.131.78.236/setup/install/86eb0821-0bb2-4677-a043-42b949185aaa/fc1ce0bb-ee5e-4f17-be27-1ac76c09df98\u001b[0m",
        "stdout_lines": [
            "",
            "     ____                  __          ____  ",
            "    / __ \\____  _____ ____/ /_  ____  / / /_ ",
            "   / /_/ / __ `/ ___/ ___/ __ \\/ __ \\/ / __/ ",
            "  / ____/ /_/ (__  |__  ) /_/ / /_/ / / /    ",
            " /_/    \\__,_/____/____/_.___/\\____/_/\\__/   ",
            "",
            " Open source password manager for teams",
            "-------------------------------------------------------------------------------",
            "\u001b[32mUser saved successfully.\u001b[0m",
            "\u001b[32mTo start registration follow the link provided in your mailbox or here: ",
            "https://104.131.78.236/setup/install/86eb0821-0bb2-4677-a043-42b949185aaa/fc1ce0bb-ee5e-4f17-be27-1ac76c09df98\u001b[0m"
        ]
    }
}

PLAY RECAP *********************************************************************************************************************************************************************************************
104.131.78.236             : ok=10   changed=8    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Now you can click on the URL and register your first admin user.

Initial Admin User Setup

Set Password

Click on the URL from the last step and you can begin to create your first username/password. At the first screen you will set your password. Be careful because there is no retyping. It will accept whatever you put in first. After inputing the password click ‘Next’.

Download Recovery Kit

The next page will automatically download a recovery kit. This will allow you to recover from losing your password. Keep this file somewhere safe to restore access to your account if needed. Then click ‘Next’.

Security Token

When being contacted by your server if you setup email, this security token will be shown to help prove the email is from the correct source. Choose three letters and a color. Then click ‘Next’.

Integrations

Now you are officially setup on your new Passbolt server. The next step is to work on getting any devices you have connected. The following have been tested with the code repo:

  • iPhone
  • Browser Extension

The process to set this up will not be a part of this post but the following documentation can be referenced for helping with iPhone/Android: documentation
You will need to import the cert for the phone to trust the passbolt server. The cert to import can be found on the desktop of the computer that deployed the Passbolt server.
~/Desktop/passbolt.crt/<ipaddress>/root/certificate.crt

Adding Users

Right now the best way to add a user using this repo is to run a command on the server:

docker-compose exec passbolt su -m -c "/usr/share/php/passbolt/bin/cake passbolt register_user -u {{ user_email }} -f {{ user_fname }} -l {{ user_lname }}

This will allow you to create users and retrieve a login URL for them to go to. No email is supported in the current setup so automated emails will not work.

Summary

In this post we created a Passbolt instance for you to save your passwords across devices. Remember to destroy it once you are finished to stop being charged. Ensure your login passwords to the instance are very secure so that no one else can login to your account.