hashicorp / vault-helm

Helm chart to install Vault and other associated components.
Mozilla Public License 2.0
1.08k stars 873 forks source link

A better way to pass the transit autounseal wrap token #898

Closed retpolanne closed 1 year ago

retpolanne commented 1 year ago

Is your feature request related to a problem? Please describe.

Context:

I want to create a local-lab for vault that should be self contained, fully automated with Terraform and running on Minikube. Currently, we have to unseal the vault instances manually by kubectl-execing onto the pods and running unseal. One thing that would be great would be to leverage autounseal through Transit Secrets Engine.

My architecture is pretty simple: I keep a vault dev server running on my host, run all the commands to create policies and a wrap token for the unseal procedure, then the pods will connect to the host in order to do the autounseal.

It's possible to do this using Helm. However, it requires a token and I'm not comfortable with how the token is currently provided.

server:
  affinity: ""
  ha:
    enabled: true
    raft: 
      enabled: true
      config: |
        ui = true

        listener "tcp" {
          tls_disable = 1
          address = "[::]:8200"
          cluster_address = "[::]:8201"
        }

        storage "raft" {
          path = "/vault/data"
        }

        service_registration "kubernetes" {}
        seal "transit" {
          address         = "http://host.minikube.internal:8200"
          token           = "SOME_SECRET_TOKEN_THAT_SHOULDNT_BE_HARDCODED_HERE"
          disable_renewal = "false"
          key_name        = "autounseal"
          mount_path      = "transit/"
          tls_skip_verify = "true"
        }

Describe the solution you'd like

Have a way to setup autounseal from values.yaml. For example:

server:
  autounseal:
    enabled: true
    transit:
      address: http://127.0.0.1:8200
      token: "SOME_SECRET_TOKEN_THAT_CAN_BE_OVERRIDEN_SOMEHOW"
      disable_renewal: false
      key_name: autounseal
      mount_path: transit
      tls_skip_verify: true

I only need transit right now, but this issue can be broken for each autoseal backend. I've provided the backends in the additional context.

Describe alternatives you've considered I tried using yaml anchors, but they can't be used for multiline strings.

I believe that passing VAULT_TOKEN with the unwrapped token from Vault 1 (where Transit Secret Engine is running) should solve this problem. As per the docs:

The seal stanza does not set the token value since it's already set as VAULT_TOKEN environment variable.

Additional context

Configs for each seal kind:

transit

seal "transit" {
  address = "http://127.0.0.1:8200"
  disable_renewal = "false"
  token = "UNWRAP_TOKEN"
  key_name = "autounseal"
  mount_path = "transit/"
  tls_skip_verify = "true"
}

awskms

seal "awskms" {
  region     = "us-west-2"
  kms_key_id = "df68263c-d9ee-44e3-afca-83cfa370c605"
}

azurekeyvault

seal "azurekeyvault" {
  client_id      = "YOUR-APP-ID"
  client_secret  = "YOUR-APP-PASSWORD"
  tenant_id      = "YOUR-AZURE-TENANT-ID"
  vault_name     = "Test-vault-XXXXXX"
  key_name       = "generated-key"
}

gcpckms

seal "gcpckms" {
  project     = "gcloud-vault-test"
  region      = "global"
  key_ring    = "test"
  crypto_key  = "vault-test"
}
retpolanne commented 1 year ago

Okay, so here's the correct way to do this:

Example values.yaml file

server:
  extraSecretEnvironmentVars:
  - envName: VAULT_TOKEN
    secretName: vault
    secretKey: VAULT_TOKEN
  affinity: ""
  ha:
    enabled: true
    raft: 
      enabled: true
      config: |
        ui = true

        listener "tcp" {
          tls_disable = 1
          address = "[::]:8200"
          cluster_address = "[::]:8201"
        }

        storage "raft" {
          path = "/vault/data"
        }

        service_registration "kubernetes" {}
        seal "transit" {
          address         = "http://host.minikube.internal:8200"
          disable_renewal = "false"
          key_name        = "autounseal"
          mount_path      = "transit/"
          tls_skip_verify = "true"
        }

On Vault 1:

# Prerequisites 
vault audit enable file file_path=audit.log
vault secrets enable transit
vault write -f transit/keys/autounseal
tee autounseal.hcl <<EOF
path "transit/encrypt/autounseal" {
   capabilities = [ "update" ]
}

path "transit/decrypt/autounseal" {
   capabilities = [ "update" ]
}
EOF
vault policy write autounseal autounseal.hcl

# Setting up the VAULT_TOKEN
unset WRAPPED_VAULT_TOKEN
unset VAULT_TOKEN
export WRAPPED_VAULT_TOKEN=`vault token create -orphan -policy="autounseal" -wrap-ttl=120 -period=24h | grep 'wrapping_token:' | awk '{print $2}'`
export VAULT_TOKEN=`VAULT_TOKEN=$WRAPPED_VAULT_TOKEN vault unwrap | grep token | awk '{print $2}' | head -1`

# Helm
kubectl create ns vault
kubectl create secret generic vault -n vault --from-literal=VAULT_TOKEN="$VAULT_TOKEN"
helm install vault hashicorp/vault -n vault -f values.yaml

For the record, vault init and raft join can be automated with this, I believe https://github.com/hashicorp/vault-helm/blob/a276600b716375b235b96a2ff289271931861a39/values.yaml#L549

andreapigatto commented 4 months ago

@retpolanne Hi! Were you able to automate all with postStart? How you run it only in a node in case of HA? Thanks!

retpolanne commented 4 months ago

Hey @andreapigatto! I haven't used vault in a long long while, so I can't respond for sure :(

andreapigatto commented 4 months ago

Hey @andreapigatto! I haven't used vault in a long long while, so I can't respond for sure :(

no problems.. thanks anyway!