From 5b56261372aa6665d2f38846081be8d3a39201e3 Mon Sep 17 00:00:00 2001 From: Mark Sagi-Kazar Date: Wed, 6 Sep 2023 15:44:26 +0200 Subject: [PATCH] feat: add new examples Signed-off-by: Mark Sagi-Kazar --- examples/README.md | 157 ++++++++++++++++++++ examples/base/kustomization.yaml | 6 + examples/base/rbac.yaml | 46 ++++++ examples/base/vault.yaml | 50 +++++++ examples/file/kustomization.yaml | 16 ++ examples/file/vault.yaml | 32 ++++ examples/kubernetes-auth/README.md | 84 +++++++++++ examples/kubernetes-auth/kustomization.yaml | 8 + examples/kubernetes-auth/vault.yaml | 40 +++++ examples/startup-secrets/kustomization.yaml | 8 + examples/startup-secrets/vault.yaml | 36 +++++ 11 files changed, 483 insertions(+) create mode 100644 examples/README.md create mode 100644 examples/base/kustomization.yaml create mode 100644 examples/base/rbac.yaml create mode 100644 examples/base/vault.yaml create mode 100644 examples/file/kustomization.yaml create mode 100644 examples/file/vault.yaml create mode 100644 examples/kubernetes-auth/README.md create mode 100644 examples/kubernetes-auth/kustomization.yaml create mode 100644 examples/kubernetes-auth/vault.yaml create mode 100644 examples/startup-secrets/kustomization.yaml create mode 100644 examples/startup-secrets/vault.yaml diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..edbaf0d3 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,157 @@ +# Vault Operator examples + +These examples demonstrate different Vault Operator features. + +## Examples + +- [Base](base/): Minimal example for launching Vault +- [File storage](file/): Persistent volumes and file storage +- [Startup secrets](startup-secrets/): Initialize Vault with secrets +- [Kubernetes auth](kubernetes-auth/): Authenticate against Vault using Kubernetes Service Accounts + +## Prerequisites + +- Ability to setup a Kubernetes cluster (eg. using [KinD](https://kind.sigs.k8s.io/)) +- kubectl +- kustomize +- [Helm](https://helm.sh/) +- [vault CLI](https://developer.hashicorp.com/vault/downloads) +- kubectl [view-secret plugin](https://github.com/elsesiy/kubectl-view-secret) _(optional)_ + +It is recommended that you check out this repository and run examples from there as some examples require additional steps (but you may be able to run some of them directly): + +```shell +git clone git@github.com:bank-vaults/vault-operator.git +cd vault-operator/examples +``` + +## Set up a Kubernetes cluster + +Vault Operator should run on recent Kubernetes versions. +We generally use [KinD](https://kind.sigs.k8s.io) for demos, but [k3d](https://k3d.io) is also a popular option. + +You can launch a local cluster using KinD by running the following command: + +```shell +kind create cluster +``` + +## Install Vault Operator + +Install the latest version of the Vault Operator: + +```shell +helm upgrade --install --wait --namespace vault-system --create-namespace vault-operator oci://ghcr.io/bank-vaults/helm-charts/vault-operator +``` + +## Install Vault + +Choose one of the examples in this folder, follow instructions (if any) in the README and install the example: + +```shell +EXAMPLE=base + +kustomize build $EXAMPLE | kubectl apply -f - +``` + +Or if you haven't checked out the repository: + +```shell +EXAMPLE=base + +kustomize build github.com/bank-vaults/vault-operator/examples/$EXAMPLE | kubectl apply -f - +``` + +> [!IMPORTANT] +> Examples are generally mutually exclusive, so make sure you don't install two of them on the same cluster at the same time. +> If you want to experiment with multiple examples, consider using [vCluster](https://www.vcluster.com/). + +## Checking Vault + +After installation, you may want to check the installation and interact with Vault. + +First, wait for Vault to become ready: + +```shell +kubectl wait pods vault-0 --for condition=Ready --timeout=120s +``` + +> [!NOTE] +> You may need to pass a namespace parameter to the above and following commands: `--namespace YOUR_NAMESPACE` + +Set the Vault token from the Kubernetes secret: + +```shell +export VAULT_TOKEN=$(kubectl get secrets vault-unseal-keys -o jsonpath={.data.vault-root} | base64 --decode) +``` + +Tell the CLI where Vault is listening: + +```shell +export VAULT_ADDR=http://127.0.0.1:8200 +``` + +> [!NOTE] +> If you are running an example with TLS configured, the address should be `https://127.0.0.1:8200`. + +Port forward to the Vault service: + +```shell +kubectl port-forward service/vault 8200 1>/dev/null & +``` + +Check Vault status: + +```shell +vault status +``` + +Open the UI (and login with the root token): + +```shell +open $VAULT_ADDR +``` + +The same commands again: + +```shell +kubectl wait pods vault-0 --for condition=Ready --timeout=120s +export VAULT_TOKEN=$(kubectl get secrets vault-unseal-keys -o jsonpath={.data.vault-root} | base64 --decode) +export VAULT_ADDR=http://127.0.0.1:8200 +kubectl port-forward service/vault 8200 1>/dev/null & +vault status +``` + +TODO: Write a script with the above commands? + +## Cleanup + +Kill background jobs: + +```shell +kill %1 +``` + +Delete the installed example: + +```shell +kustomize build $EXAMPLE | kubectl delete -f - +``` + +Delete unseal keys: + +```shell +kubectl delete secret vault-unseal-keys +``` + +Delete the Operator: + +```shell +helm -n vault-system delete vault-operator +``` + +Delete the cluster: + +```shell +kind delete cluster +``` diff --git a/examples/base/kustomization.yaml b/examples/base/kustomization.yaml new file mode 100644 index 00000000..e41dae66 --- /dev/null +++ b/examples/base/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - rbac.yaml + - vault.yaml diff --git a/examples/base/rbac.yaml b/examples/base/rbac.yaml new file mode 100644 index 00000000..235cc0d2 --- /dev/null +++ b/examples/base/rbac.yaml @@ -0,0 +1,46 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: vault + +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: vault +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["*"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "update", "patch"] + +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: vault +roleRef: + kind: Role + name: vault + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: vault + +--- +# This binding allows the deployed Vault instance to authenticate clients +# through Kubernetes ServiceAccounts (if configured so). +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: vault-auth-delegator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: + - kind: ServiceAccount + name: vault + namespace: default diff --git a/examples/base/vault.yaml b/examples/base/vault.yaml new file mode 100644 index 00000000..ad024da4 --- /dev/null +++ b/examples/base/vault.yaml @@ -0,0 +1,50 @@ +apiVersion: vault.banzaicloud.com/v1alpha1 +kind: Vault +metadata: + name: vault +spec: + size: 1 + + image: hashicorp/vault:1.14.1 + + # 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. + # See https://www.vaultproject.io/docs/configuration/ for more information. + config: + storage: + inmem: {} + listener: + tcp: + address: "0.0.0.0:8200" + tls_disable: true + ui: true + log_level: debug + + # See: https://bank-vaults.dev/docs/cli-tool/#example-external-vault-configuration + externalConfig: + policies: + - name: allow_secrets + rules: | + path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } + + secrets: + - path: secret + type: kv + description: General secrets. + options: + version: 2 + + auth: + - type: kubernetes + roles: + # Default role assumed by workloads by default + # Allow every pod in the default namespace to use the secret kv store + - name: default + bound_service_account_names: ["*"] + bound_service_account_namespaces: ["default"] + policies: ["allow_secrets"] + ttl: 1h diff --git a/examples/file/kustomization.yaml b/examples/file/kustomization.yaml new file mode 100644 index 00000000..d3af40c4 --- /dev/null +++ b/examples/file/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../base/ + +patches: + - path: vault.yaml + - patch: |- + - op: remove + path: /spec/config/storage/inmem + target: + group: vault.banzaicloud.com + version: v1alpha1 + kind: Vault + name: vault diff --git a/examples/file/vault.yaml b/examples/file/vault.yaml new file mode 100644 index 00000000..76e304d1 --- /dev/null +++ b/examples/file/vault.yaml @@ -0,0 +1,32 @@ +apiVersion: vault.banzaicloud.com/v1alpha1 +kind: Vault +metadata: + name: vault +spec: + # Use local disk to store Vault file data, see config section. + volumes: + - name: vault-file + persistentVolumeClaim: + claimName: vault-file + + volumeMounts: + - name: vault-file + mountPath: /vault/file + + volumeClaimTemplates: + - metadata: + name: vault-file + spec: + # https://kubernetes.io/docs/concepts/storage/persistent-volumes/#class-1 + # storageClassName: "" + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: 1Gi + + config: + storage: + file: + path: /vault/file diff --git a/examples/kubernetes-auth/README.md b/examples/kubernetes-auth/README.md new file mode 100644 index 00000000..6bc0068c --- /dev/null +++ b/examples/kubernetes-auth/README.md @@ -0,0 +1,84 @@ +# Kubernetes auth + +This example demonstrates how to authenticate against Vault using a Kubernetes Service Account token. +It also contains an example for writing policies targeting the accessor (identity behind the token). + +## Check access + +Run the following command to open a shell in the `default` namespace: + +```shell +kubectl run vault-shell --rm -i --tty --env "VAULT_ADDR=http://vault:8200" --image hashicorp/vault:1.14.1 -- sh +``` + +Exchange the Service Account token for a Vault token: + +```shell +export VAULT_TOKEN=$(vault write -field=token auth/kubernetes/login role=default jwt=$(cat /run/secrets/kubernetes.io/serviceaccount/token)) +``` + +## Simple policy + +Write some data into Vault: + +```shell +vault kv put shared/foo bar=baz +``` + +Read the secret back: + +```shell +vault kv get shared/foo +``` + +## Accessor-based policy + +The second policy limits access to `namespaces/NAMESPACE` (namespace in this case is `default`, because that's where the shell pod is running). + +Try writing some data into Vault: + +```shell +vault kv put namespaces/not-default/foo bar=baz +``` + +You should see a permission denied error: + +``` +Error writing data to namespaces/data/vault/foo: Error making API request. + +URL: PUT http://vault:8200/v1/namespaces/data/vault/foo +Code: 403. Errors: + +* 1 error occurred: + * permission denied +``` + +Try writing some data into the right path: + +```shell +vault kv put namespaces/default/foo bar=baz +``` + +Read the data back: + +```shell +vault kv get namespaces/default/foo +``` + +Try reading from another path: + +```shell +vault kv get namespaces/not-default/foo +``` + +It should fail again: + +``` +Error reading namespaces/data/not-default/foo: Error making API request. + +URL: GET http://vault:8200/v1/namespaces/data/not-default/foo +Code: 403. Errors: + +* 1 error occurred: + * permission denied +``` diff --git a/examples/kubernetes-auth/kustomization.yaml b/examples/kubernetes-auth/kustomization.yaml new file mode 100644 index 00000000..d49c02b6 --- /dev/null +++ b/examples/kubernetes-auth/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../base/ + +patches: + - path: vault.yaml diff --git a/examples/kubernetes-auth/vault.yaml b/examples/kubernetes-auth/vault.yaml new file mode 100644 index 00000000..1f19ae9b --- /dev/null +++ b/examples/kubernetes-auth/vault.yaml @@ -0,0 +1,40 @@ +apiVersion: vault.banzaicloud.com/v1alpha1 +kind: Vault +metadata: + name: vault +spec: + # See: https://bank-vaults.dev/docs/cli-tool/#example-external-vault-configuration + externalConfig: + policies: + - name: allow_shared_secrets + rules: | + path "shared/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } + + - name: allow_namespaced_secrets + rules: | + path "namespaces/data/{{identity.entity.aliases.${ accessor `kubernetes/` }.metadata.service_account_namespace}}/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } + + secrets: + - path: shared + type: kv + options: + version: 2 + + - path: namespaces + type: kv + options: + version: 2 + + auth: + - type: kubernetes + roles: + # Allow every pod in the default namespace to use the secret kv store + - name: default + bound_service_account_names: ["*"] + bound_service_account_namespaces: ["default"] + policies: ["allow_shared_secrets", "allow_namespaced_secrets"] + ttl: 1h diff --git a/examples/startup-secrets/kustomization.yaml b/examples/startup-secrets/kustomization.yaml new file mode 100644 index 00000000..d49c02b6 --- /dev/null +++ b/examples/startup-secrets/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../base/ + +patches: + - path: vault.yaml diff --git a/examples/startup-secrets/vault.yaml b/examples/startup-secrets/vault.yaml new file mode 100644 index 00000000..6a98d988 --- /dev/null +++ b/examples/startup-secrets/vault.yaml @@ -0,0 +1,36 @@ +apiVersion: vault.banzaicloud.com/v1alpha1 +kind: Vault +metadata: + name: vault +spec: + # See: https://bank-vaults.dev/docs/cli-tool/#example-external-vault-configuration + externalConfig: + secrets: + - path: secret + type: kv + 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