# 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>" ```