Deploy F5 HTTPS VIPs using Terraform and HashiCorp Vault PKI Secrets engine

Sebastian Maniak
5 min readMay 24, 2022

--

Happy May24 weekend here in Canada… I had some cycles, so I thought I would share some more F5 #BIG-IP infrastructure as code to the world using @Hashicorp Terraform and Vault.

Objective: Fully deploy an F5 “production ready” Secure Virtual IP configuration using terraform and integrating Vault PKI Engine.

Here is the following code to deploy this in AWS. https://github.com/maniak-academy/medium-f5-terraform-vault

Diagram

The following diagram outlines a “production” like deployment of managing F5 with infrastructure as code and zero trust in mind.

Components

Here are the components used.

Terraform Cloud

Terraform Cloud is HashiCorp’s managed service offering. It eliminates the need for unnecessary tooling and documentation for practitioners, teams, and organizations to use Terraform in production. Provision infrastructure in a remote environment that is optimized for the Terraform workflow.

Terraform cloud is host the state of the environment and any secrets we require.

BIGIP F5 deployed with AS3

“Application Services 3 Extension (referred to as AS3 Extension or more often simply AS3) is a flexible, low-overhead mechanism for managing application-specific configurations on a BIG-IP system. AS3 uses a declarative model, meaning you provide a JSON declaration rather than a set of imperative commands. The declaration represents the configuration which AS3 is responsible for creating on a BIG-IP system. AS3 is well-defined according to the rules of JSON Schema, and declarations validate according to JSON Schema. AS3 accepts declaration updates via REST (push), reference (pull), or CLI (flat file editing)” — from here

HashiCorp Vault

“Vault is an identity-based secrets and encryption management system. A secret is anything that you want to tightly control access to, such as API encryption keys, passwords, or certificates. Vault provides encryption services that are gated by authentication and authorization methods. Using Vault’s UI, CLI, or HTTP API, access to secrets and other sensitive data can be securely stored and managed, tightly controlled (restricted), and auditable. “ — from here

Vault PKI Secret Engine

“The PKI secrets engine generates dynamic X.509 certificates. With this secrets engine, services can get certificates without going through the usual manual process of generating a private key and CSR, submitting to a CA, and waiting for a verification and signing process to complete. Vault’s built-in authentication and authorization mechanisms provide the verification functionality.” — from here

Let’s Build our lab

Prerequisites

Setup Vault

For this we will use Vault Dev instance for easy of use

  1. Start Vault in a new terminal
vault server -dev -dev-root-token-id root

2. Export an environment variable for the vault CLI to address the Vault server.

export VAULT_ADDR=http://127.0.0.1:8200

3. Export an environment variable for the vault CLI to authenticate with the Vault server.

export VAULT_TOKEN=root

Configure Vault

  1. Configure PKI Engine
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki

2. Generate root CA and Configure CA and CRL URL

vault write -field=certificate pki/root/generate/internal \
common_name="example.com" \
ttl=87600h > CA_cert.crt# Configure the CA and CRL URL
vault write pki/config/urls \
issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
crl_distribution_points="$VAULT_ADDR/v1/pki/crl"

3. Generate Intermediate CA

vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=43800h pki_int

4. Execute the following command to generate an intermediate and save the CSR as pki_intermediate.csr

vault write -format=json pki_int/intermediate/generate/internal \
common_name="example.com Intermediate Authority" \
| jq -r '.data.csr' > pki_intermediate.csr

5.Sign the intermediate certificate with the root CA private key, and save the generated certificate as intermediate.cert.pem.

vault write -format=json pki/root/sign-intermediate csr=@pki_intermediate.csr \
format=pem_bundle ttl="43800h" \
| jq -r '.data.certificate' > intermediate.cert.pem

6. Once the CSR is signed and the root CA returns a certificate, it can be imported back into Vault.

vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem

7. Create a Role named example-dot-com which allows subdomains.

vault write pki_int/roles/example-dot-com \
allowed_domains=”example.com” \
allow_subdomains=true \
ttls="10m" \
max_ttl=”30m”

Done… let’s move onto the next part.

Build Terraform Code

Let’s dive into the terraform code to deploy a HTTPS web application. The code is located in my repo https://github.com/maniak-academy/medium-f5-terraform-vault

I will go over the main components of the code, feel free download the code from my repo to get a better understanding how the variables are map.

Let’s first build a main.tf file. The first thing we are going to is add the terraform providers required [“F5Networks/bigip and hashicorp/vault”].

Next step is to configure the providers, we are connecting to our dev instance of vault and f5 bigip that’s deployed in my vmware lab.

terraform {
required_providers {
bigip = {
source = "F5Networks/bigip"
version = "1.13.1"
}
vault = {
source = "hashicorp/vault"
version = "3.5.0"
}
}
}
provider "vault" {
address = var.vaultaddress
token = var.vault_token
}
provider "bigip" {
address = var.bigipmgmt
username = var.bigipmgmtuser
password = var.bigippass
}

The next part of the main.tf file is the module app. This is going to be where we define our F5 VIP configuration objects, like the VIP address, pool members and the cert name.

module "app" {
source = "./app"
tenant = "local-demo"
vip_address = "10.99.99.10"
common_name = "test.example.com"
pki_name = "example-dot-com"
pool_members = ["10.10.0.1", "10.10.0.2"]
}

Take a look /app/main.tf. this is brain of the configuration file. We are doing 3 things here.

  1. We are using vault_pki_secret_backend_cert resource to get specific cert required for this app.
  2. We are using locals with templatefile to generate our f5 AS3 JSON configuration baed off the tempalte file “https.tpl”
  3. We are pushing the configuration using the bigip_as3 resource.
resource "vault_pki_secret_backend_cert" "app" {
backend = "pki_int"
name = var.pki_name
common_name = var.common_name
}
resource "bigip_as3" "app_services" {
as3_json = local.as3_json
}
resource "local_file" "as3" {
content = local.as3_json
filename = "${path.module}/as3-bigip.json"
}
locals {
as3_json = templatefile("./as3templates/https.tpl", {
TENANT = var.tenant
VIP_ADDRESS = var.vip_address
MY_POOLMEMBERS = jsonencode(var.pool_members)
CERT = jsonencode(vault_pki_secret_backend_cert.app.certificate)
KEY = jsonencode(vault_pki_secret_backend_cert.app.private_key)
CA_CHAIN = jsonencode(vault_pki_secret_backend_cert.app.ca_chain)
})
}

To make use of the code in my repo you will need to edit the terraform.tfvars if your values.

bigipmgmt     = "192.168.86.46"
bigipmgmtuser = "admin"
bigippass = "W3e098!"
vault_token = "hvs.Wj7FJ8yYwUZGkrUB4x"
vaultaddress = "http://192.168.86.69:8200"

End Results:

When you initiate terraform init and terraform apply, the following configuration will be automatically deployed on your F5 BIGIP. This code allows you to manage your entire f5 infrastructure using Code!

--

--

No responses yet