# Bank-Vaults: everything Azure guide
In this tutoral, we are going to start an AKS cluster, deploy the [Vault Operator](https://github.com/bank-vaults/vault-operator), the [Vault Secrets Webhook](https://github.com/bank-vaults/vault-secrets-webhook) and create a Vault instance which is configured to use [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/) to store Vault's root and unseal tokens, [Azure Storage](https://learn.microsoft.com/en-us/azure/storage/) to persist Vault's data and the [Azure Auth method](https://developer.hashicorp.com/vault/docs/auth/azure) for the Webhook to authenticate against Vault.
Prerequisites:
- Access to Azure cloud with a subscription
- `azure-cli` installed on your machine
## Step 1: Create Azure resources
First and foremost, ensure you are logged in to your Azure account with `azure-cli`:
```bash!
az login --tenant <YourTenantName>
[
{
"cloudName": "AzureCloud",
"homeTenantId": "<YourHomeTenantId>",
"id": "<YourSubscriptionId>",
"isDefault": true,
"managedByTenants": [],
"name": "<YourSubscriptionName>",
"state": "Enabled",
"tenantId": "<YourTenantId>",
"user": {
"name": "<YourUserName>",
"type": "user"
}
}
]
```
We will need `<YourSubscriptionId>` and `<YourTenantId>` later.
Then, if you don't already have a `Resource group` you would like to use, create a new one:
```bash
az group create --name "bank-vaults-test-rg" --location "EastUS"
{...}
```
### Create an AKS cluster
```bash!
# create cluster
az aks create --resource-group "bank-vaults-test-rg" --name "bank-vaults-test-cluster" --generate-ssh-keys
{...}
# write credentials to kubeconfig
az aks get-credentials --resource-group "bank-vaults-test-rg" --name "bank-vaults-test-cluster"
# if you need to look at cluster information again
az aks show --resource-group "bank-vaults-test-rg" --name "bank-vaults-test-cluster"
```
### Create an App Registration and a Client secret
We will use this `App Registration` as the resource for generating MSI access tokens for authentication. A more detailed guide for this can be found [here](https://learn.microsoft.com/en-us/azure/healthcare-apis/register-application-cli-rest).
```bash!
# create App Registration and only return with its Application Id
az ad app create --display-name "bank-vaults-test-ar" --query appId --output tsv
<YourAppRegistrationApplicationId>
# create Service Principal for your App Registration
az ad sp create --id "<YourAppRegistrationApplicationId>" --query id --output tsv
<YourEnterpriseApplicationObjectID>
# create secret
az ad app credential reset --id "<YourAppRegistrationApplicationId>" --append --display-name "bank-vaults-test-secret" --query password --output tsv
# The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
<YourAppRegistrationClientSecret>
# authorize the Service Principal to read resources in your Resource Group
az role assignment create --assignee "<YourEnterpriseApplicationObjectID>" --scope "/subscriptions/<YourSubscriptionId>/resourceGroups/MC_bank-vaults-test-rg_bank-vaults-test-cluster_eastus" --role Reader
{...}
```
### Create a Key Vault and permit the AKS cluster to access it
```bash!
# create Azure Key Vault
az keyvault create --resource-group "bank-vaults-test-rg" --name "bank-vaults-test-kv" --location "EastUS"
{...}
# get our AKS cluster's Object ID
az aks show --resource-group "bank-vaults-test-rg" --name "bank-vaults-test-cluster" --query "identityProfile.kubeletidentity.objectId" --output tsv
<YourAKSClusterObjectID>
# set policy
az keyvault set-policy --name "bank-vaults-test-kv" --object-id <YourAKSClusterObjectID> --secret-permissions all --key-permissions all --certificate-permissions all
{...}
```
### Create Storage account and a Container
```bash!
# create storage account
az storage account create \
--name "bankvaultsteststorage" \
--resource-group "bank-vaults-test-rg" \
--location "EastUS" \
--sku "Standard_RAGRS" \
--kind "StorageV2"
{...}
# get storage account key
az storage account keys list --account-name "bankvaultsteststorage" --query "[0].value" --output tsv
<YourStorageAccountKey>
# create container
az storage container create \
--name "bank-vaults-test-container" \
--account-name "bankvaultsteststorage"
{...}
```
## Step 2: Install Bank-Vaults components
We are going to [install](https://bank-vaults.dev/docs/operator/#deploy-operator) the [Vault Operator](https://github.com/bank-vaults/vault-operator), [install](https://bank-vaults.dev/docs/mutating-webhook/deploy/#deploy-the-mutating-webhook) the mutating [Webhook](https://github.com/bank-vaults/vault-secrets-webhook) on the AKS cluster we just created, prepare a `Vault` custom resource and apply it so it would use Azure resources for storing credentials, data and for authentication.
### Install Vault Operator
```bash!
# install Vault Operator
helm upgrade --install --wait vault-operator oci://ghcr.io/bank-vaults/helm-charts/vault-operator
```
### Install Vault Secrets Webhook
```bash!
# create a new namespace and install the Vault Secrets Webhook in it
kubectl create namespace vault-infra
kubectl label namespace vault-infra name=vault-infra
helm upgrade --install --wait vault-secrets-webhook oci://ghcr.io/bank-vaults/helm-charts/vault-secrets-webhook --namespace vault-infra
```
### Start a pre-configured Vault instance
Create a `cr-azure.yaml` resource definition file and copy-paste this content below into it. Replace `<YourStorageAccountKey>`, `<YourTenantId>`, `<YourAppRegistrationObjectId>`, `<YourAppRegistrationClientSecret>`, `<YourSubscriptionId>` and `<YourAKSClusterObjectID>` with the values acquired above, and also the `spec.unsealConfig.azure.keyVaultName`, `spec.config.storage.azure.accountName`, `spec.config.storage.azure.container` fields if you used other names for these Azure resources than in this guide.
The Vault Operator can put some initial secrets into Vault when configuring it (`spec.externalConfig.startupSecrets`), which we will utilize to be able to test it with a deployment right away in the next step.
```yaml!
apiVersion: "vault.banzaicloud.com/v1alpha1"
kind: "Vault"
metadata:
name: "vault"
spec:
size: 1
image: "hashicorp/vault:1.14.1"
# Describe where you would like to store the Vault unseal keys and root token in Azure KeyVault.
unsealConfig:
azure:
keyVaultName: "bank-vaults-test-kv" # name of the Key Vault we created
# Specify the ServiceAccount where the Vault Pod and the Bank-Vaults configurer/unsealer is running
serviceAccount: vault
# A YAML representation of a final vault config file, this config represents a backend config in Azure.
# See https://www.vaultproject.io/docs/configuration/ for more information.
config:
storage:
azure:
accountName: "bankvaultsteststorage" # name of the storage we created
accountKey: "<YourStorageAccountKey>" # storage account key we listed in a previous step
container: "bank-vaults-test-container" # name of the container we created
environment: "AzurePublicCloud"
listener:
tcp:
address: "0.0.0.0:8200"
tls_cert_file: /vault/tls/server.crt
tls_key_file: /vault/tls/server.key
api_addr: https://vault.default:8200
telemetry:
statsd_address: localhost:9125
ui: true
# See: https://banzaicloud.com/docs/bank-vaults/cli-tool/#example-external-vault-configuration
# The repository also contains a lot examples in the deploy/ and operator/deploy directories.
externalConfig:
policies:
- name: allow_secrets
rules: path "secret/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
auth:
- type: azure
path: azure
config:
tenant_id: "<YourTenantId>"
resource: "https://management.azure.com/"
client_id: "<YourAppRegistrationApplicationId>" # App Registration Application (client) ID
client_secret: "<YourAppRegistrationClientSecret>" # App Registration generated secret value
roles:
# Add roles for azure identities
# See https://www.vaultproject.io/api/auth/azure/index.html#create-role
- name: default
policies: allow_secrets
bound_subscription_ids:
- "<YourSubscriptionId>"
bound_service_principal_ids:
- "<YourAKSClusterObjectID>" # AKS cluster Object ID
secrets:
- path: secret
type: kv
description: General secrets.
options:
version: 2
# Allows writing some secrets to Vault (useful for development purposes).
# See https://www.vaultproject.io/docs/secrets/kv/index.html for more information.
startupSecrets:
- type: kv
path: secret/data/accounts/aws
data:
data:
AWS_ACCESS_KEY_ID: secretId
AWS_SECRET_ACCESS_KEY: s3cr3t
- type: kv
path: secret/data/dockerrepo
data:
data:
DOCKER_REPO_USER: dockerrepouser
DOCKER_REPO_PASSWORD: dockerrepopassword
- type: kv
path: secret/data/mysql
data:
data:
MYSQL_ROOT_PASSWORD: s3cr3t
MYSQL_PASSWORD: 3xtr3ms3cr3t
```
Once the resource definition is filled out with our data, apply it together with some RBAC rules:
```bash!
# apply RBAC rules
kubectl kustomize https://github.com/bank-vaults/vault-operator/deploy/rbac | kubectl apply -f -
# apply deployment manifest
kubectl apply -f cr-azure.yaml
```
After the Vault instance successfully created, you can access Vault with the Vault CLI from within your terminal after running this:
```bash!
export VAULT_TOKEN=$(az keyvault secret download --file azure --name vault-root --vault-name bank-vaults-test-kv; cat azure; rm azure)
kubectl get secret vault-tls -o jsonpath="{.data.ca\.crt}" | base64 --decode > $PWD/vault-ca.crt
export VAULT_CACERT=$PWD/vault-ca.crt
export VAULT_ADDR=https://127.0.0.1:8200
kubectl port-forward service/vault 8200 &
```
## Step 3: Create a deployment that would use Azure auth
Finally, we will start test deployment and check if the secrets were successfully injected into its pods!
Create a resource definition file `deployment.yaml` for our deployment and copy these contents into it:
```yaml!
apiVersion: apps/v1
kind: Deployment
metadata:
name: bank-vaults-test
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: bank-vaults-test
template:
metadata:
labels:
app.kubernetes.io/name: bank-vaults-test
annotations:
vault.security.banzaicloud.io/vault-addr: "https://vault:8200"
vault.security.banzaicloud.io/vault-skip-verify: "true"
vault.security.banzaicloud.io/vault-role: "default"
vault.security.banzaicloud.io/vault-path: "azure"
vault.security.banzaicloud.io/vault-auth-method: "azure"
spec:
containers:
- name: alpine
image: alpine
command:
- "sh"
- "-c"
- "echo $AWS_SECRET_ACCESS_KEY && echo $MYSQL_PASSWORD && echo going to sleep... && sleep 10000"
env:
- name: AWS_SECRET_ACCESS_KEY
value: vault:secret/data/accounts/aws#AWS_SECRET_ACCESS_KEY
- name: MYSQL_PASSWORD
value: vault:secret/data/mysql#${.MYSQL_PASSWORD}
resources:
limits:
memory: "128Mi"
cpu: "100m"
```
Apply it and then watch for its logs - are the secrets injected in by the Webhook present?
```bash!
kubectl appply -f deployment.yaml
kubectl logs -l app.kubernetes.io/name=bank-vaults-test --follow
...
s3cr3t
3xtr3ms3cr3t
going to sleep...
```
## Step 4: Clean up
If you created the aforementioned Azure resources just for testing purposes, you migh want to destroy them to reduce cloud costs:
```bash!
# delete Resource group with the AKS Cluster, Key Vault, Storage and Container etc.
az group delete --name "bank-vaults-test-rg"
# delete App Registration
az ad app delete --id "<YourAppRegistrationApplicationId>"
```
## One more thing
You can also configure an [Azure secrets engine](https://developer.hashicorp.com/vault/docs/secrets/azure) with Vault Operator, if you add to the vault custom resource manifest file something like this:
```bash
az ad sp create-for-rbac --role Contributor --scopes /subscriptions/<YourSubscriptionId>
Creating 'Contributor' role assignment under scope '/subscriptions/<YourSubscriptionId>'
The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
{
"appId": "<YourServicePrincipalId>",
"displayName": "azure-cli-xxx",
"password": "<YourSecretValue>",
"tenant": "<YourTenantId>"
}
```
```yaml!
spec:
externalConfig:
secrets:
- path: azure
type: azure
description: Azure Secret Backend
configuration:
roles:
- name: dns-role
ttl: 1h
azure_roles: '[{"role_name": "Contributor", "scope": "/subscriptions/<YourSubscriptionId>/resourceGroups/MC_bank-vaults-test-rg_bank-vaults-test-cluster_eastus"}]'
config:
- subscription_id: "<YourSubscriptionId>"
tenant_id: "<YourTenantId>"
client_id: "<YourServicePrincipalId>"
client_secret: "<YourSecretValue>"
```