The Genesis Blog

Deploying a BOSH to Microsoft Azure Using Genesis and Terraform

1 Aug 2019

Introduction

BOSH is an effective way to manage your infrastructure and Azure is a great infrastructure to manage, but before you have a BOSH director, you need to bootstrap Azure to a point where you can deploy a BOSH Director to it. Namely, we need an Azure App Registration to use as an automation account, a properly configured virtual network, and a virtual machine inside the network from which we can deploy the BOSH director.

Getting Azure Situated

Creating an App Registration

Both Terraform and BOSH perform tasks without user input, and therefore they require an automation account that can access the resources they need to manipulate. Azure implements these in the form of what they call App Registrations.

You will need to create an App Registration, generate a client secret for authenticating to that App Registration, and then grant said App Registration Contributor access to the subscription in which you would like resources to be created. During this process, you will need to collect a few details:

Setting up Terraform

Now that we have automation credentials, we can start standing up infrastructure using Terraform. Terraform binaries and documentation can be found at https://terraform.io.

We've already made a basic Terraform file for you that can stand up your control plane if given a few extra parameters. You can set up your working directory for terraform as follows:

~/work/repos → git clone git@github.com:genesis-community/terraforms.git Cloning into 'terraforms'... remote: Enumerating objects: 26, done. remote: Counting objects: 100% (26/26), done. remote: Compressing objects: 100% (18/18), done. remote: Total 113 (delta 7), reused 23 (delta 4), pack-reused 87 Receiving objects: 100% (113/113), 1.38 MiB | 3.32 MiB/s, done. Resolving deltas: 100% (41/41), done. ~/work/repos → mkdir terraform-work ~/work/repos → cp terraforms/controlplane/azure/azure.tf terraform-work/ ~/work/repos → cp terraforms/controlplane/azure/terraform.tfvars.example terraform-work/terraform.tfvars ~/work/repos → cd terraform-work/ ~/work/repos/terraform-work → terraform init

Initializing the backend...

Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "azurerm" (terraform-providers/azurerm) 1.32.1...

The following providers do not have any version constraints in configuration, so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below.

Input variables for this deployment can be provided by putting their values into the terraform.tfvars file. Minimally, you'll need to edit the subscription_id, tenant_id, client_id, and client_secret. These are all values you should have taken note earlier during the app registration steps.

Once configured, run terraform apply from the directory with your azure.tf and terraform.tfvars file.

~/work/repos/terraform-work → pwd /Users/tom/work/repos/terraform-work ~/work/repos/terraform-work → terraform apply

An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create

Terraform will perform the following actions:

...all of the resources to be created...

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

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

... many creation lines ...

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

Outputs:

bastion-box-ip-address = 13.82.181.177 bastion-box-username = ubuntu bastion-box-password = abCdEfGhiJKLmnoPqRStUvWXyz123456 dns-servers = [ "1.1.1.1", "1.0.0.1", ] network-security-group-name = genesis-sg recommended-BOSH-director-IP = 10.0.0.5 resource-group-name = genesis subnet-CIDR = 10.0.0.0/24 subnet-gateway = 10.0.0.1 subnet-name = genesis-controlplane-subnet virtual-network-name = genesis-network

Following this command, Terraform will have stood up a resource group, virtual network, network security groups, and most importantly, a bastion box virtual machine from which you can continue your work. The terraform script will also install various tools and libraries on the bastion box that Genesis, BOSH, and Cloud Foundry need.

You can see from the example output above (and similarly in your actual output) that some output variables are printed at the end of the apply. You will want to copy those output values somewhere for now, as they contain the answers to many of the questions that Genesis will ask you later.

Setting Up Your Bastion Host

Once your bastion box is created, you can ssh into it to begin working from it. The user, password, and IP address can be found in the terraform output variables.

~/work/repos/terraform-work → ssh ubuntu@13.82.181.177 The authenticity of host '13.82.181.177 (13.82.181.177)' can't be established. ECDSA key fingerprint is SHA256:vvBs1voA6+R6fDyrPf0+YpH1go9HEv3ThxE4ionswR8. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '13.82.181.177' (ECDSA) to the list of known hosts. ubuntu@12.82.181.177's password: Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.18.0-1024-azure x86_64)

Last login: Mon Aug 12 15:44:03 2019 from 71.186.231.155

Before proceeding, you will need to set up the basics of your Git config. Run the following with the proper values substituted:

git config --global user.name "YOURNAME" git config --global user.email "YOUREMAIL"

Starting a Local Vault Instance

Genesis stores deployment secrets in Vault, a secure, encrypted-at-rest credentials store from Hashicorp. Genesis has opinions about how the Vault should be organized, so it's not suggested to colocate the Genesis secret store on a pre-existing Vault.

We use the Safe CLI to interact with Vault in general. The Terraform script has installed it on your bastion host. We're going to use safe to quickly set up a temporary local Vault instance that Genesis can use until we are able to set up a more permanent Vault later, via BOSH.

safe will run this Vault as a foreground process, so you will need to open up a separate shell session / tmux pane on the jumpbox and run:

safe local --memory --as temp-vault

Safe will output the target name of the new Vault, target it, and authenticate to it automatically.

Deploying a New Proto-BOSH

First, create an deployments directory in which to store your various Genesis deployment folders. Then, change to that directory and initialize a new Genesis deployment repository:

ubuntu@bastion:~$ mkdir ~/deployments ubuntu@bastion:~$ cd ~/deployments ubuntu@bastion:~/deployments$ genesis init bosh -k bosh --vault temp-vault

Verifying availability of selected vault...ok

Downloading Genesis kit bosh (latest version)...

Initialized empty Genesis repository in ./bosh-deployments - using vault at http://127.0.0.1:8201 (insecure) - using the bosh/1.4.0 kit.

cd into the newly created directory. Now we need to set up a new proto-BOSH director deployment using genesis new. Genesis new takes a positional argument which is the name of the environment that you're creating the deployment in. For the purpose of this tutorial, we'll call ours test-eastus-controlplane. Genesis will walk you through a series of questions about the deployment you're about to make. Answers to most of these questions were output at the end of your terraform apply. Azure credential information can be found in the terraform.tfvars file that you set up in your terraform-work directory outside of the bastion box. An example of a successful genesis new call is seen below.

ubuntu@bastion:~/deployments$ cd bosh-deployments ubuntu@bastion:~/deployments/bosh-deployments$ genesis new test-eastus-controlplane Setting up new environment test-eastus-controlplane...

Using vault at http://127.0.0.1:8201. Verifying availability...ok

Is this a proto-BOSH director? [y|n] > y

We are deploying this BOSH without the aid of an existing BOSH, so this is a Proto-BOSH director

What static IP do you want to deploy this BOSH director on?

10.0.0.5

What network should this BOSH director exist in (in CIDR notation)?

10.0.0.0/24

What default gateway (IP address) should this BOSH director use?

10.0.0.1

This network information is output from your Terraform script. Assuming that your Terraform script is configured to use the 10.0.0.0/24 CIDR, then the gateway would be 10.0.0.1, and the first available IP (after the network address, gateway, Azure reserved IPs, and bastion host) would be 10.0.0.5.

What DNS servers should BOSH use? (leave value empty to end) 1st value > 1.1.1.1 2nd value > 1.0.0.1 3rd value >

Select the DNS servers that you would like this BOSH director and all VMs deployed by this BOSH director to use. For this example, we're using Cloudflare's public DNS.

What IaaS will this BOSH director orchestrate? 1) VMWare vSphere 2) Amazon Web Services 3) Microsoft Azure 4) Google Cloud Platform 5) OpenStack 6) BOSH Warden

Select choice > Microsoft Azure

What is your Azure Client ID?

01234567-89ab-cdef-0123-456789abcdef What is your Azure Client Secret? clientsecret [hidden]: clientsecret [confirm]:

What is your Azure Tenant ID?

01234567-89ab-cdef-0123-456789abcdef

What is your Azure Subscription ID?

01234567-89ab-cdef-0123-456789abcdef

If you've gotten this far into this guide, then you should most likely select Microsoft Azure as your infrastructure. The Azure Client ID, Client Secret, Tenant ID, and Subscription ID were all things you should have taken note of earlier when setting up your App Registration. Also, you should have placed this information in your terraform.tfvars.

What Azure Resource Group will BOSH be deploying VMs into?

genesis

What security group should be used as the BOSH default security group?

genesis-sg

What is the name of your Azure Virtual Network?

genesis-network

What is the name of the Azure subnet that the BOSH will be placed in?

genesis-controlplane-subnet

These resources should all have been created by your Terraform script. The names of the created resources were output at the end of the terraform apply. All of the names are prefixed with the name you chose for your resource group.

Would you like to edit the environment file? [y|n] > n - auto-generating credentials (in secret/test/eastus/controlplane/bosh)... - auto-generating certificates (in secret/test/eastus/controlplane/bosh)... New environment test-eastus-controlplane provisioned!

To deploy, run this:

 genesis deploy 'test-eastus-controlplane'

The command will then spend some time generating certificates and secrets for the deployment to use. These will get stored in the local Vault and made accessible by the safe utility.

An environment file named after your environment name (e.g. test-eastus-controlplane.yml) will be created. This contains non-sensitive information about your deployment. It is safe to store this file in version control. To deploy your newly-configured BOSH deployment, you can now run:

ubuntu@bastion:~/deployments/bosh-deployments$ genesis deploy test-eastus-controlplane Compiling package 'ruby-2.4-r4/0cdc60ed7fdb326e605479e9275346200af30a25'... Finished (00:05:47) Compiling package 'boshazurecpi/afc0bf467dd0d4489f757d788065ab4d4f977ce4'... Finished (00:01:55) Installing packages... Finished (00:00:01) Rendering job templates... Finished (00:00:01) Installing job 'azure_cpi'... Finished (00:00:00) Finished installing CPI (00:07:45)

Starting registry... Finished (00:00:00) Uploading stemcell 'bosh-azure-hyperv-ubuntu-xenial-go_agent/315.26'... Finished (00:02:24)

Started deploying Creating VM for instance 'bosh/0' from stemcell 'bosh-stemcell-90cb8ae1-9202-4555-8416-18fe08a1cb19'... Finished (00:02:20) Waiting for the agent on VM 'agentid:16d9e7ca-f62d-442c-43b2-9dd270517140;resourcegroupname:genesis' to be ready... Finished (00:01:00) Creating disk... Finished (00:00:13) Attaching disk 'caching:None;diskname:bosh-disk-data-612ab183-3042-4ec3-a077-e58a4e01ada8;resourcegroupname:genesis' to VM 'agentid:16d9e7ca-f62d-442c-43b2-9dd270517140;resourcegroupname:genesis'... Finished (00:01:07) Rendering job templates... Finished (00:00:36) Compiling package 'golang/b348840d6ee6de87fdd43e4792fdbe1af734039b'... Finished (00:00:49) Compiling package 'bpm-runc/cb758414ed267820880c6bf1ca57d7467c2d70bf'... Finished (00:02:02) Compiling package 'ruby-2.4-r5/726cbb2214e138b576700db6a30698edb2b994e2'... Finished (00:02:12) Compiling package 'mysql/de7350b5d6d835f758a62c0b3a8f07d3f0150d67abfa0da3967bd1127fada4c6'... Finished (00:00:47) Compiling package 'libpq/b3fead55dd7c9fa83be2412b24db84d2b04dbdb5dd0583ee7e9afddbb200659a'... Finished (00:00:23) Compiling package 'ruby-2.4-r4/0cdc60ed7fdb326e605479e9275346200af30a25'... Finished (00:02:05) Compiling package 'openjdk1.8.0/d2d85d44c6f0ee050ef1fb0149ce3da575234ad6'... Finished (00:00:12) Compiling package 'gonats/a32f561770ebdc422c2f9955c7614c23900b9edc62aec51a6b48adc636516802'... Finished (00:00:01) Compiling package 's3cli/4b6a4e65f277e1e4cdd9bfd8330de14ea28e9e5762a304f2d3a35f47958d7376'... Finished (00:00:01) Compiling package 'nginx/d9c13905876ac2bc3f62657048750257794ecc53121ad7cd92583d3ef292b8b8'... Finished (00:00:48) Compiling package 'bpm/d7c8de76cea8201f6cdf37d4f848b0a52c9c5798'... Finished (00:00:12) Compiling package 'uaautils/90097ea98715a560867052a2ff0916ec3460aabb'... Finished (00:00:00) Compiling package 'director/35121e0b2f3354dcfccbed5ea52ea2ccb14dd0d0b90cdd5c4be0787cbdd96ca6'... Finished (00:01:10) Compiling package 'boshazurecpi/afc0bf467dd0d4489f757d788065ab4d4f977ce4'... Finished (00:00:48) Compiling package 'uaa/58ad7562f1d34ad24256fff92b3a241f8e101a2a'... Finished (00:00:56) Compiling package 'postgres-9.4/ee3022bfae2cb7f7454aed9e28fe7715765b9a0086ef2045219f7a4e16baca81'... Finished (00:03:49) Compiling package 'bosh-gcscli/a03b1fc29fd357b8e3023193c87ae9ee49db052965efe5b3d9bff3538ed2df4b'... Finished (00:00:01) Compiling package 'registry/1d74c7cbca2216cdf7f51bc74eca2c831012dc25b5b53d66b3412042edb032ef'... Finished (00:00:50) Compiling package 'credhub/0481a83e36b6179f4fc9f28088c4cd2ac3aa870a'... Finished (00:00:23) Compiling package 'verifymultidigest/2405293bf44933ac48362d7e109fc38ea4469b962cf62715533ecca53c28bf7b'... Finished (00:00:01) Compiling package 'davcli/100c52066493ef0d766c464c9cdd811c902a555013543bd16b62cf59ba5c72eb'... Finished (00:00:01) Compiling package 'lunaclient/b922e045db5246ec742f0c4d1496844942d6167a'... Finished (00:00:03) Compiling package 'health_monitor/8f3a84d055a292d385f4f2f0df42ba25eb424ccff6a3854e1209668fec263295'... Finished (00:00:26) Updating instance 'bosh/0'... Finished (00:01:58) Waiting for instance 'bosh/0' to be running... Finished (00:02:34) Running the post-start scripts 'bosh/0'... Finished (00:00:02) Finished deploying (00:28:04)

Stopping registry... Finished (00:00:00) Cleaning up rendered CPI jobs... Finished (00:00:00)

Succeeded

test-eastus-controlplane BOSH Director deployed!

For details about the deployment, run

 genesis info test-eastus-controlplane

To set up a named alias for this director, run

 genesis do test-eastus-controlplane -- alias

To log into the BOSH director, as the admin user, run

 genesis do test-eastus-controlplane -- login

If this is a new BOSH director, you can upload stemcells by running

 genesis do test-eastus-controlplane -- upload-stemcells

To log in to the BOSH director, there is a hook script provided for you by genesis. Hook scripts can be run with genesis do:

ubuntu@bastion:~/deployments/bosh-deployments$ genesis do test-eastus-controlplane -- login

Uploading Your Cloud Config

The BOSH cloud config contains shared information about all the deployments you'll be deploying to your control plane environment. This includes the network IP allocations, VM sizes, disk sizes, availability zone configurations, and compilation VM configuration.

The terraform script, as a part of its creation of the bastion host, has put a cloud config file for you at $HOME/deployments/director-configs. All you need to do is upload it.

First, make sure that you're logged into bosh. Then run

bosh -e test-eastus-controlplane update-cloud-config $HOME/deployments/director-configs/controlplane.yml

Now your cloud config should be uploaded and ready to go.