Skip to content

Vault

Vault is an open source secrets manager and identity provider created by hashicorp. It runs in Kubernetes with a DynamoDB backend that's encrypted with KMS with point in time recovery enabled.

Authentication Backends

Your infrastructure will be set up with Vault running in the EKS cluster. It will come with multiple Authentication Backends enabled.

Token authentication

Your first login to Vault will be with the root token that is provided to you at the end of your kubefirst cluster create. This root token has full administrative permission throughout Vault.

To log in with the root token, find the vault.token field in your ~/.kubefirst file and copy the value that starts with hvs.. Then navigate to your vault instance in your browser, select Token and paste the token in the password field.

While logged in with the root token, navigate to the secret: Secrets -> Users -> kbot

This secret is the userpass/oidc password for the kubefirst bot user kbot. Copy this value to your clipboard, log out of vault and let's try using the userpass authentication backend in the next section.

Username authentication (human users)

Now that you have collected the kbot password, let's log out and back into Vault, this time using the kbot bot account.

When logging in with users instead of tokens, select method Username as the login method on the login screen. Enter kbot as the username, and paste the password you collected in the Password field and log in.

This is the login experience that your team will use when authenticating with Vault. Initially, there will only be a singular kbot user created that represents the kubefirst bot account. You can pull request additional admins and developers from your team onto the platform, and they will all log in using the Username method.

Once a user is logged into vault with Username auth, they will be automatically provided single-sign-on access to argo workflows, argo cd, console, and gitlab applications.

Kubernetes authentication

The external-secrets-operator application will be preconfigured with a service account that can pull secrets from your cluster's vault instance. This is accomplished by leveraging the kubernetes/kubefirst/ auth backend. By default, external-secrets will be able to pull your cluster secrets, and make them available as native kubernetes secrets for your applications to leverage.

Additional auth methods

There are other authentication schemes available to you as well: https://www.vaultproject.io/docs/auth

Secrets Setup for Applications

Storing secrets in Vault

While logged into Vault, navigate to secrets path secret/development/metaphor.

Here you can see we have two secrets stored at named SECRET_ONE and SECRET_TWO with two "secret values". These two values are obviously not actually sensitive and are for demonstration purposes only. Let's explore how secrets work.

Creating Kubernetes Secrets From Vault Secrets

If you look in your new metaphor repository in gitlab or github, you'll find a helm template file at path metaphor/charts/metaphor/templates/external-secrets.yaml

apiVersion: "external-secrets.io/v1alpha1"
kind: ExternalSecret
metadata:
  name: {{ template "metaphor.fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
  target:
    name: {{ template "metaphor.fullname" . }}
  secretStoreRef:
    kind: ClusterSecretStore
    name: vault-secrets-backend
  refreshInterval: "10s"
  data:
    - remoteRef:
        key: {{ .Values.vaultSecretPath }}
        property: SECRET_ONE
      secretKey: SECRET_ONE
    - remoteRef:
        key: {{ .Values.vaultSecretPath }}
        property: SECRET_TWO
      secretKey: SECRET_TWO

This is going to be a very common file type for you on the kubefirst platform. This kubernetes resource deploys with metaphor, connecting to the vault-secrets-backend cluster secret store, and pulls secrets from the path specified in the values.yaml property vaultSecretPath. You can either pull all secrets from Vault into the kubernetes secret, or as this secret demonstrates, you can also specify exactly which specific key/value pairs to pull when creating the secret.

The result will be a native kubernetes secret, which can be used by your application. Since the path is driven by helm values.yaml values, the source for these secrets can be different in your different environments. For example, when you go to your gitops repository and look at gitops/components/staging/metaphor/values.yaml you'll see on the last line that we're pulling the staging secrets from the staging path in vault.

metaphor:
  ingress:
    enabled: true
    annotations:
      kubernetes.io/ingress.class: nginx
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
    hosts:
      - host: metaphor-staging.feedkray.com
        paths:
          - /
    tls:
    - secretName: metaphor-tls
      hosts:
        - metaphor-staging.feedkray.com
  vaultMountPoint: kubefirst
  vaultSecretPath: staging/metaphor

Confirming Your Kubernetes Secrets

Applying the above ExternalSecret resource to your Kubernetes namespace is enough to produce a Kubernetes secret which will stay in sync with Vault's values. Let's confirm:

1. Get all secrets in the staging namespace:

kubectl -n staging get secrets

NAME                               TYPE                                  DATA   AGE
default-token-z7crd                kubernetes.io/service-account-token   3      13h
metaphor-frontend-sa-token-668gq   kubernetes.io/service-account-token   3      12h
metaphor-frontend-tls              kubernetes.io/tls                     2      12h
metaphor-go-sa-token-bx2gk         kubernetes.io/service-account-token   3      12h
metaphor-go-staging                Opaque                                2      12h
metaphor-go-tls                    kubernetes.io/tls                     2      12h
metaphor-sa-token-v964z            kubernetes.io/service-account-token   3      12h
metaphor-staging                   Opaque                                2      12h
metaphor-tls                       kubernetes.io/tls                     2      12h

2. Get the yaml of the one named metaphor-staging:

kubectl -n staging get secret metaphor-staging -oyaml

apiVersion: v1
data:
  SECRET_ONE: c3RhZ2luZyBzZWNyZXQgMQ==
  SECRET_TWO: c3RhZ2luZyBzZWNyZXQgMg==
immutable: false
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"external-secrets.io/v1alpha1","kind":"ExternalSecret","metadata":{"annotations":{},"labels":{"argocd.argoproj.io/instance":"metaphor-staging","chart":"metaphor-0.1.0-rc.e54452a0"},"name":"metaphor-staging","namespace":"staging"},"spec":{"data":[{"remoteRef":{"key":"staging/metaphor","property":"SECRET_ONE"},"secretKey":"SECRET_ONE"},{"remoteRef":{"key":"staging/metaphor","property":"SECRET_TWO"},"secretKey":"SECRET_TWO"}],"refreshInterval":"10s","secretStoreRef":{"kind":"ClusterSecretStore","name":"vault-secrets-backend"},"target":{"name":"metaphor-staging"}}}
    reconcile.external-secrets.io/data-hash: fdc2f634a31c8e93dd8d47e940aa7939
  creationTimestamp: "2022-10-18T04:21:57Z"
  labels:
    argocd.argoproj.io/instance: metaphor-staging
    chart: metaphor-0.1.0-rc.e54452a0
  name: metaphor-staging
  namespace: staging
  ownerReferences:
  - apiVersion: external-secrets.io/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: ExternalSecret
    name: metaphor-staging
    uid: 890fe79f-f48a-4dac-85c6-ac790ffc4147
  resourceVersion: "21526"
  uid: 1c2c9cd8-6aed-4e65-8e5c-57d3fd578b4d
type: Opaque

3. Confirm that it's your value from vault:

echo "c3RhZ2luZyBzZWNyZXQgMQ==" | base64 -d

staging secret 1% 

Using Those Secrets in Your App

Now that you have native Kubernetes secrets available, you can use them however you choose. Our metaphor example uses them as environment variables as shown here:

Note: There are a ton of other ways secrets can be leveraged in your app, like using secrets as files on pods, or storing your dockerhub login.