
Gerenciar secrets nativamente no Kubernetes não é seguro. No Kubernetes, secrets são apenas texto em base64 que qualquer pod em execução pode consumir.
Aviso:
Este tutorial foi pensado para você entender cada componente da configuração, passo a passo. Nada impede que você use terraform para montar tudo, mas seguir cegamente uma configuração tão crítica pode gerar problemas difíceis de resolver sem esse entendimento mais profundo.

Claro, dá para criptografar um secret no Kubernetes, mas esse secret só fica criptografado em repouso. Quando ele é montado dentro do Pod, vira apenas um arquivo ou variável de ambiente que pode ser acessado facilmente de dentro do Pod. Em caso de violação, os dados podem ser comprometidos se alguém tiver acesso ao Pod ou até mesmo ao namespace onde ele está rodando, via kubectl.
O HashiCorp Vault é uma forma segura de gerenciar secrets, além de auditar e revogar o acesso a eles. Uma coisa é instalar e usar o Vault, outra bem diferente é consumir esses secrets em um Pod.
Este post mostra como instalar o Vault no GKE com Terraform e Helm. Para consumir esses secrets, leia também meu outro post sobre como consumir secrets do Vault de forma transparente em um Pod.
Essa abordagem é mais simples de gerenciar se você só precisa do Vault e não precisa dos recursos avançados do Consul, como o Consul template com Vault.
Neste tutorial, vou mostrar como instalar um Vault em alta disponibilidade usando o Google Cloud Storage (GCS) como backend, com TLS de ponta a ponta.
Observação:
Crie a configuração do Vault separada por ambiente, para testar atualizações com mais segurança e isolar os ambientes entre si.
Não recomendo expor o Vault como um serviço. Caso precise acessá-lo, use o comando:
$ kubectl port-forward vault-0 8200:8200e acesse a UI em https://127.0.0.1:8200, conforme detalhado abaixo.
Se você tiver VMs que precisam acessar esse Vault, use VPC peering, já que serviços e pods usam IPs nativos — esse cenário não está coberto aqui.
Tutorial:
Resumo:
- Criar certificados TLS para o Vault
- Criar um Bucket no GCS para o backend de armazenamento do Vault
- Criar keyring KMS e chave de criptografia para o auto-unseal do Vault.
- Criar service accounts para o Vault acessar o KMS e o backend de armazenamento GCS.
- Instalar o Helm chart oficial do HashiCorp Vault via helm tillerless.
Criando certificados TLS para o Vault:

Uma das recomendações de hardening para produção é que a comunicação entre o Vault e os clientes seja criptografada por TLS, tanto no tráfego de entrada quanto no de saída.
Vamos criar um certificado para:
- O endereço do serviço Vault no Kubernetes.
- 127.0.0.1
Vamos usar o CloudFlare SSL toolkit ( cfssl e cfssljson) para gerar esses certificados.
A instalação requer uma instalação funcional do Go 1.12+ e um GOPATH configurado corretamente.
Importante!: garanta que o bin do GOPATH está no seu path:
export PATH=$GOPATH/bin:$PATHInstalando o CloudFlare SSL ToolKit:
go get -u github.com/cloudflare/cfssl/cmd/cfsslgo get -u github.com/cloudflare/cfssl/cmd/cfssljsonInicializar uma Autoridade Certificadora (CA):
$ mkdir vault-ca && cd vault-caCrie os arquivos da CA:
Arquivo de configuração da CA com expiração de 5 anos
$ cat <<EOF > ca-config.json{ "signing": { "default": { "expiry": "8760h" }, "profiles": { "default": { "usages": ["signing", "key encipherment", "server auth", "client auth"], "expiry": "8760h" } } }}EOFSolicitação de Assinatura da CA:
$ cat <<EOF > ca-csr.json{ "hosts": [\ "cluster.local"\ ], "key": { "algo": "rsa", "size": 2048 }, "names": [\ {\ "C": "US",\ "L": "NewYork",\ "O": "Kubernetes",\ "OU": "CA",\ "ST": "NewYork"\ }\ ]}EOFSolicitação de Assinatura do Certificado VAULT, a ser assinada pela CA acima: nota: altere o namespace do Vault se não for o namespace default
$ cat <<EOF > vault-csr.json{ "CN": "Vault-GKE", "hosts": [\ "127.0.0.1",\ "vault.default.svc.cluster.local"\ ], "key": { "algo": "rsa", "size": 2048 }, "names": [\ {\ "C": "US",\ "L": "NewYork",\ "O": "Innovia",\ "OU": "Vault",\ "ST": "NewYork"\ }\ ]}EOFVocê pode, claro, alterar as informações do certificado na seção "names" como preferir.
Execute o comando abaixo para inicializar a CA usando o arquivo que você acabou de editar:
$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca2019/11/12 16:35:01 [INFO] generating a new CA key and certificate from CSR2019/11/12 16:35:01 [INFO] generate received request2019/11/12 16:35:01 [INFO] received CSR2019/11/12 16:35:01 [INFO] generating key: rsa-20482019/11/12 16:35:01 [INFO] encoded CSR2019/11/12 16:35:01 [INFO] signed certificate with serial number 425581644650417483788325060652779897454211028144Crie uma chave privada e assine o certificado TLS:
$ cfssl gencert \ -ca=ca.pem \ -ca-key=ca-key.pem \ -config=ca-config.json \ -profile=default \ vault-csr.json | cfssljson -bare vault2019/11/12 16:36:33 [INFO] generate received request2019/11/12 16:36:33 [INFO] received CSR2019/11/12 16:36:33 [INFO] generating key: rsa-20482019/11/12 16:36:34 [INFO] encoded CSR2019/11/12 16:36:34 [INFO] signed certificate with serial number 311973563616303179057952194819087555625015840298Nesse ponto, você deve ter os seguintes arquivos no diretório de trabalho atual:
ca-key.pemca.pemvault-key.pemvault.pemGuarde os arquivos da CA em local seguro: você vai precisar deles para reassinar o certificado quando expirar (a CA vale 5 anos, e o Vault, 1 ano).
Crie um secret para o TLS do Vault e o CA.pem:
kubectl create secret generic vault-tls \ --from-file=ca.pem \ --from-file=vault.pem \ --from-file=vault-key.pemDefina o Projeto GCP para o restante deste tutorial:
$ export GCP_PROJECT=<your_project_id>Habilitando as APIs do GCP necessárias para este tutorial:
$ gcloud services enable \ cloudapis.googleapis.com \ cloudkms.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ iam.googleapis.com \ --project ${GCP_PROJECT}Operation "operations/acf.8e126724-bbde-4c0d-b516-5dca5b8443ee" finished successfully.Backend de armazenamento do Vault
Google Cloud Storage
Em modo HA, os servidores Vault têm dois estados adicionais: standby e active. Em um cluster Vault, apenas uma instância fica active e atende a todas as requisições (leituras e escritas), e todos os nós em standby redirecionam as requisições para o nó active.
Vamos criar o bucket no GCS com o comando gsutil. Os nomes de bucket precisam ser únicos em todo o Google Cloud, então escolha um nome exclusivo.
$ export GCS_BUCKET_NAME=mycompany-vault-data$ gsutil mb gs://$GCS_BUCKET_NAME$ gsutil versioning set on gs://$GCS_BUCKET_NAMEMesmo com os dados criptografados em trânsito e em repouso, defina permissões adequadas no bucket para limitar a exposição. Vale a pena criar uma service account que restrinja, via permissões IAM, a interação do Vault com o Google Cloud apenas aos objetos do bucket de armazenamento.
Auto unseal do Vault

Quando o Vault é reiniciado, ele sobe selado e criptografado. Para usá-lo, é preciso fazer o unseal. Existe um recurso novo, o auto unseal, que lê automaticamente as master keys e o root token do CloudKMS.
Criar Keyring KMS e Crypto Key:
Nesta seção, vamos criar o keyring KMS e a chave para criptografar e descriptografar as master keys e o root token do Vault:
Crie o keyring kms vault-helm-unseal-kr:
$ gcloud kms keyrings create vault-helm-unseal-kr \ --location global \ --project ${GCP_PROJECT}Crie a chave de criptografia:
$ gcloud kms keys create vault-helm-unseal-key \ --location global \ --keyring vault-helm-unseal-kr \ --purpose encryption \ --project ${GCP_PROJECT}Criar as service accounts do GCP e permissões IAM para o Vault
Configure as variáveis:
$ export VAULT_SA_NAME=vault-server; export VAULT_SA=$VAULT_SA_NAME@$GCP_PROJECT.iam.gserviceaccount.comCrie a service account do servidor Vault:
$ gcloud iam service-accounts create $VAULT_SA_NAME \ --display-name "Vault server service account" \ --project ${GCP_PROJECT}Crie a chave da service account do servidor Vault (arquivo JSON de credenciais):
$ gcloud iam service-accounts keys create \ --iam-account $VAULT_SA /tmp/vault_gcs_key.jsoncreated key [be22cfe6e30f3a3fcfc6ebaa23ca3ba905dd60ab] of type [json] as [/tmp/vault_gcs_key.json] for [[email protected]] Crie o secret para armazenar a service account do Google do Vault$ kubectl create secret generic vault-gcs \ --from-file=/tmp/vault_gcs_key.jsonsecret/vault-gcs createdConceda acesso ao Bucket GCS de armazenamento do Vault:
$ gsutil iam ch \ serviceAccount:${VAULT_SA}:objectAdmin \ gs://${GCS_BUCKET_NAME}Conceda acesso à chave kms do Vault:
$ gcloud kms keys add-iam-policy-binding \ vault-helm-unseal-key \ --location global \ --keyring vault-helm-unseal-kr \ --member serviceAccount:${VAULT_SA} \ --role roles/cloudkms.cryptoKeyEncrypterDecrypter \ --project ${GCP_PROJECT}Updated IAM policy for key [vault-helm-unseal-key].bindings:- members: - serviceAccount:[email protected] role: roles/cloudkms.cryptoKeyEncrypterDecrypteretag: BwWZ6sIYovk=version: 1Nota:Se por algum motivo você excluiu a service account e a recriou, é preciso excluir a política IAM na chave; caso contrário, vá direto para Obter o chart oficial do HashiCorp Vault$ gcloud kms keys get-iam-policy vault-helm-unseal-key --location global --keyring vault-helm-unseal-kr > kms-policy.yaml edite o arquivo de política, remova os members em binding e salve o arquivobindings:etag: BwWXQz4HjuI=version: 1Reaplique a política:
$ gcloud kms keys set-iam-policy vault-helm-unseal-key --location global --keyring vault-helm-unseal-kr kms-policy.yamlBaixe o chart oficial do Vault da HashiCorp:

nota:
A partir da versão 0.3.0, existe uma integração do Kubernetes com o Vault que injeta secrets automaticamente no Pod, renderizando o secret como um arquivo em um volume. Recomendo fortemente usar meu vault secrets webhook, que é uma forma mais segura de injetar um secret em um Pod e ainda automatiza o consumo dos secrets.
export CHART_VERSION=0.3.0Baixe e descompacte o chart:
$ wget https://github.com/hashicorp/vault-helm/archive/v$CHART_VERSION.tar.gz && tar zxf v$CHART_VERSION.tar.gz && rm v$CHART_VERSION.tar.gzConfigurando o values.yaml do chart:
O gist a seguir tem placeholders para substituição de variáveis.
global: tlsDisable: false
server: extraEnvironmentVars: GOOGLE_APPLICATION_CREDENTIALS: /vault/userconfig/vault-gcs/vault_gcs_key.json extraVolumes: - type: secret name: vault-gcs path: "/vault/userconfig" - type: secret name: vault-tls path: "/etc/tls"
authDelegator: enabled: true
ha: enabled: true config: | ui = true listener "tcp" { tls_disable = 0 tls_cert_file = "/etc/tls/vault-tls/vault.pem" tls_key_file = "/etc/tls/vault-tls/vault-key.pem" tls_client_ca_file = "/etc/tls/vault-tls/ca.pem" tls_min_version = "tls12" address = "[::]:8200" cluster_address = "[::]:8201" } storage "gcs" { bucket = "GCS_BUCKET_NAME" ha_enabled = "true" } seal "gcpckms" { project = "GCP_PROJECT" region = "global" key_ring = "vault-helm-unseal-kr" crypto_key = "vault-helm-unseal-key" }Use o comando abaixo para criar um novo arquivo de values chamado vault-gke-values.yaml:
$ curl -s https://gist.githubusercontent.com/innovia/53c05bf69312706fc93ffe3bb685b223/raw/adc169605984da8ba82082191c8f631579b1b199/vault-gke-values.yaml | sed "s/GCP_PROJECT/$GCP_PROJECT/g" | sed "s/GCS_BUCKET_NAME/$GCS_BUCKET_NAME/g" > vault-helm-$CHART_VERSION/vault-gke-values.yamlConfira o arquivo gerado para garantir que o projeto e o bucket GCS estão corretos.
$ cat vault-helm-$CHART_VERSION/vault-gke-values.yaml | grep -E 'bucket|project'bucket = "<COMPANY>-vault-data"project = "ami-playground"Usando helm 2.x:
Se você não tiver o tiller instalado no cluster, dá para pular essa configuração instalando o plugin tillerless do helm, que sobe um tiller local na sua máquina e faz o helm apontar para ele. Caso contrário, vá direto para a seção instalar o chart do Vault abaixo.
Instale o plugin tillerless do helm:
Se você ainda não tem o helm, instale com:
$ brew install helm@2Inicialize apenas o cliente para que o servidor tiller não seja instalado:
helm init --client-onlyinstale o plugin helm-tillerlesshelm plugin install https://github.com/rimusz/helm-tillerinicie o tiller via helm$ helm tiller startInstalled Helm version v2.16.1Copied found /usr/local/bin/tiller to helm-tiller/binHelm and Tiller are the same version!Starting Tiller...Tiller namespace: kube-systemUsando helm 3:
$ brew install helmInstale o chart do Vault:
nota: se estiver usando helm 3, a saída não vai listar os recursos.
$ helm upgrade --install vault -f vault-helm-$CHART_VERSION/vault-gke-values.yaml vault-helm-$CHART_VERSIONrelease "vault" does not exist. Installing it now.NAME: vaultLAST DEPLOYED: Wed Nov 13 15:41:55 2019NAMESPACE: defaultSTATUS: DEPLOYEDRESOURCES:==> v1/ConfigMapNAME AGEvault-config 0s==> v1/ServiceNAME AGEvault 0s==> v1/ServiceAccountNAME AGEvault 0s==> v1/StatefulSetNAME AGEvault 0s==> v1beta1/ClusterRoleBindingNAME AGEvault-server-binding 0s==> v1beta1/PodDisruptionBudgetNAME AGEvault 0sNOTES:Thank you for installing HashiCorp Vault!Now that you have deployed Vault, you should look over the docs on usingVault with Kubernetes available here:https://www.vaultproject.io/docs/Your release is named vault. To learn more about the release, try:$ helm status vault $ helm get vaultO Vault deve subir e ficar em estado não inicializado.Os warnings a seguir são OK, já que o Vault ainda não foi inicializado:
=> Vault server started! Log data will stream in below:2019-12-17T19:07:37.937Z [INFO] proxy environment: http_proxy= https_proxy= no_proxy=2019-12-17T19:07:38.909Z [INFO] core: stored unseal keys supported, attempting fetch2019-12-17T19:07:39.037Z [WARN] failed to unseal core: error="stored unseal keys are supported, but none were found"2019-12-17T19:07:44.038Z [INFO] core: stored unseal keys supported, attempting fetch2019-12-17T19:07:44.080Z [INFO] core: autoseal: seal configuration missing, but cannot check old path as core is sealed: seal_type=recovery2019-12-17T19:07:44.174Z [WARN] failed to unseal core: error="stored unseal keys are supported, but none were found"---kubectl describe pod vault-0Events: Type Reason Age From Message ---- ------ ---- ---- ------- ... Warning Unhealthy 3s (x9 over 27s) kubelet, minikube Readiness probe failed: Key ValueInicializar o Vault com auto unseal do KMS
Abra um port-forward para o Vault com o comando:
$ kubectl port-forward vault-0 8200:8200 > /dev/null & export PID=$!; echo "vault port-forward pid: $PID"Conecte-se ao Vault usando o certificado CA.pem:
$ export VAULT_ADDR=https://127.0.0.1:8200; export VAULT_CACERT=$PWD/ca.pemmeu vault ca.pem, por exemplo, está em:VAULT_CACERT: /Users/ami/vault-gke-medium/ca.pemInstale o cliente vault (use a mesma versão do servidor):
$ brew install vaultVerifique o status:
$ vault statusKey Value--- -----Recovery Seal Type gcpckmsInitialized falseSealed trueTotal Recovery Shares 0Threshold 0Unseal Progress 0/0Unseal Nonce n/aVersion n/aHA Enabled trueAgora inicialize o Vault:
vault operator initRecovery Key 1: 33nCanHWgYMR/VPj6bNQdHXJiayL6WeB8Ourx4kHYNaXRecovery Key 2: IMf7RjptFxtGQUbEWUWehanCBiSY7VhElkM7rRVxczGcRecovery Key 3: zGuzk/PhNet9OHL4cW2H7d3XypDxfwWXkmajclLPklK4Recovery Key 4: nCFS0dt0cNGB2LWk0F+3Vmz9TbVNpeIsXbIXDbRarlnTRecovery Key 5: 9GxXr/6T8OJWJrWqyHQxayR0BAK+WTdbT870AzKEFl2VInitial Root Token: s.1ukhSgycySjZUJRD0bZjSEitSuccess! Vault is initializedRecovery key initialized with 5 key shares and a key threshold of 3. Pleasesecurely distribute the key shares printed above.Guarde essas chaves em segurança.
Confiando na autoridade certificadora autoassinada:
Como criamos o ca.pem por conta própria, ele não é confiável por padrão, já que não faz parte do bundle de CAs que vem com o seu computador.
Dá para adicionar a confiança seguindo as instruções abaixo, conforme seu sistema operacional.
Mac OS:
Definir "always trust" para a CA permite abrir a UI do Vault no navegador sem erros:
$ sudo security add-trusted-cert -d -k /Library/Keychains/System.keychain $VAULT_CACERTWindows 10:
Siga as instruções para adicionar o certificado aos publicadores confiáveis:
Configurando a autenticação do backend do Kubernetes com o Vault
Agora que o Vault está no ar e em alta disponibilidade, podemos seguir em frente e conectá-lo ao Kubernetes.
Vamos usar uma service account para fazer o login inicial do Vault no Kubernetes.
O token dessa service account será configurado dentro do Vault usando o vault CLI.
Essa service account tem uma permissão especial chamada "system:auth-delegator", que permite ao Vault repassar a service account do pod para o Kubernetes para autenticação. Uma vez autenticado, o Vault devolve um token de login para o cliente, que então conversa com o Vault e obtém os secrets de que precisa.
O cliente usa o token de login e faz login no Vault para obter o secret.
O Vault verifica um mapeamento entre uma vault role, service account, namespace e a política para liberar ou negar o acesso.
Vamos criar a service account vault-reviewer para isso.
https://gist.github.com/innovia/5435f2336e4dd0045dbb5842880b3334#file-vault-reviewer-yaml
Atenção: se você configurou o Vault em outro namespace, atualize este arquivo conforme necessário.
kubectl apply -f vault-reviewer.yamlHabilite o backend de auth do Kubernetes:
$ vault login$ vault auth enable kubernetesSuccess! Enabled kubernetes auth method at: kubernetes/Configure o Vault com o token e a ca do vault-reviewer:
nota: se você configurou o Vault em outro namespace, use a flag -n após cada comando kubectl.
$ VAULT_SA_TOKEN_NAME=$(kubectl get sa vault-reviewer -o jsonpath="{.secrets[*]['name']}")$ SA_JWT_TOKEN=$(kubectl get secret "$VAULT_SA_TOKEN_NAME" -o jsonpath="{.data.token}" | base64 --decode; echo)$ SA_CA_CRT=$(kubectl get secret "$VAULT_SA_TOKEN_NAME" -o jsonpath="{.data['ca\.crt']}" | base64 --decode; echo)$ vault write auth/kubernetes/config token_reviewer_jwt="$SA_JWT_TOKEN" kubernetes_host=https://kubernetes.default kubernetes_ca_cert="$SA_CA_CRT"Success! Data written to: auth/kubernetes/configRequisitos básicos para um pod acessar um secret:
- O Pod precisa ter uma service account
- O secret CA.pem do Vault precisa existir no namespace em que o Pod está rodando
- É preciso existir uma política com permissão mínima de leitura no secret
path "secret/foo" { capabilities = ["read"]}- É preciso criar uma vault role no Vault:
vault write auth/kubernetes/role/<role_name> \ bound_service_account_names=<service_account_name> \ bound_service_account_namespaces=<service_account_namespace> \ policies=<policy_name>Isso conclui a configuração do HashiCorp Vault no GKE. Recomendo fortemente configurar os vault secrets webhooks para consumir secrets do Vault de forma transparente, com base em apenas algumas anotações.
Como configurar a UI do Vault com Identity-Aware Proxy (IAP) via load balancer

O Identity-Aware Proxy é uma forma de autenticar um usuário sem precisar configurar uma VPN ou um Bastion SSH.
Se quiser configurar um load balancer para o serviço com Identity-Aware Proxy, siga os passos abaixo. Caso contrário, dá para acessar a UI do Vault via kubectl port-forward vault-0 8200.
O processo a seguir não vincula um usuário Google ao Vault de forma alguma — ele serve apenas como autenticação multifator. Existe uma forma de usar JWT para autenticação no Vault, mas isso permite que qualquer usuário do seu domínio escolha uma role, o que é menos seguro…
Observação:
Você ainda precisa do certificado autoassinado para o próprio serviço do Vault. O certificado do load balancer é necessário para habilitar o IAP e o https.
Pré-requisitos:
- É preciso criar um certificado para o load balancer via Google Managed certificate ou como um secret do Kubernetes.
https://cloud.google.com/load-balancing/docs/ssl-certificates
- O domínio precisa ser verificado nas ferramentas para webmasters do Google
- É preciso criar um IP estático global e uma entrada de DNS
(se você estiver usando o serviço externalDNS, isso não é necessário)
$ gcloud compute addresses create vault-ui --globalVocê pode criar um certificado usando o YAML a seguir:
https://gist.github.com/innovia/71c219692b003e97bc72feeeb5bc8442
$ kubectl apply -f managed-cert.yamlDepois de criar, aguarde de 15 a 20 minutos para que o status mude de Provisioning para Active.
Verifique o status do certificado:
$ kubectl describe ManagedCertificate vault-ui-certificateName: vault-ui-certificateNamespace: defaultLabels: <none>Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"networking.gke.io/v1beta1","kind":"ManagedCertificate","metadata":{"annotations":{},"name":"vault-ui-certificate","namespac...API Version: networking.gke.io/v1beta1Kind: ManagedCertificateMetadata: Creation Timestamp: 2020-01-13T23:10:28Z Generation: 3 Resource Version: 7120865 Self Link: /apis/networking.gke.io/v1beta1/namespaces/default/managedcertificates/vault-ui-certificate UID: e35e7a1b-3659-11ea-ae90-42010aa80174Spec: Domains: vault.ami-playground.doit-intl.comStatus: Certificate Name: mcrt-9462e1f4-6dd6-4cf2-8769-9693ba29789e Certificate Status: Active Domain Status: Domain: vault.ami-playground.doit-intl.com Status: Active Expire Time: 2020-04-12T15:12:29.000-07:00Events: <none>Configurando o IAP para o GKE:
Você pode optar por seguir as instruções completas em vez dos passos resumidos abaixo:
Configure o IAP para o seu domínio na tela de consentimento OAuth e crie as credenciais do cliente.
Depois de criar o cliente, copie o client ID e adicione-o ao campo authorized redirect URIs no seguinte formato:
https://iap.googleapis.com/v1/oauth/clientIds/<CLIENT_ID>:handleRedirectCrie o secret que será usado pelo backend config:
kubectl create secret generic my-secret --from-literal=client_id=client_id_key \ --from-literal=client_secret=client_secret_keyCrie um backend config para o IAP:
https://gist.github.com/innovia/4485a253f15cd824d0e6d2a19230a603
Habilite a seção no fim dos arquivos vault-gke.yaml e confira se os valores do IP estático global e do DNS do host estão atualizados.
Observação:
Você precisa excluir a instalação do Vault e recriá-la com o helm, já que o ingress do GKE tem problemas para atualizar ingresses existentes.
Resumindo o arquivo de values yaml:
- habilitamos o serviço da UI do Vault na porta 443 e o expomos via NodePort
- configuramos o serviço do Vault com o IAP via backend config
- habilitamos o ingress com um IP estático global e o DNS como host mapeado a ele
- desabilitamos o HTTP no load balancer
- configuramos a comunicação entre o load balancer e os pods do Vault para ser apenas https
- configuramos o managed certificate para o load balancer, para que ele funcione como um listener HTTPS
Após o deploy, ao consultar a página do IAP, você verá os erros e warnings a seguir (talvez veja os dois backend services com ERROR se estiver usando uma rede VPC compartilhada; o teste real é checar a URL da UI do Vault no navegador).

O primeiro erro é referente ao backend padrão (aquele que serve os 404s); o erro é apenas um indicativo de que o IAP não vai estar ativo em nenhuma página 404, o que é o comportamento esperado.
O outro é só um warning. Se você clicar nele, vai ver algo como:

Significa apenas que o GCP detectou que algumas regras de firewall vão contornar o IAP, como redes internas e a comunicação do load balancer com o backend do Vault.
Selecione default/vault na página do IAP e, no painel de informações à esquerda, adicione os membros que precisarão de acesso à vault-ui via load balancer.
Adicione o membro com a permissão "IAP-secured Web App User" para liberar o acesso à UI do Vault.