## Install SSCSI Driver 1. Install SSCSI Driver Operator with default option from OCP Operator hub. ![image](https://hackmd.io/_uploads/H1LUwcTCgl.png) ![image](https://hackmd.io/_uploads/SyFuDqp0xe.png) 2. Create ClusterCSIDriver object called `secrets-store.csi.k8s.io` ```yaml= apiVersion: operator.openshift.io/v1 kind: ClusterCSIDriver metadata: name: secrets-store.csi.k8s.io spec: managementState: Managed ``` ## Install Vault for test 1. Install helm on bastion ```bash= curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh ``` 2. Install Vault via hem chart Add the HashiCorp Helm Repository ``` helm repo add hashicorp https://helm.releases.hashicorp.com ``` Update your Helm Repositories ``` helm repo update ``` Create a namespace for Vault ``` oc new-project hashicorp-vault ``` Create a SCC for the CSI driver ``` oc adm policy add-scc-to-user privileged \ system:serviceaccount:hashicorp-vault:vault-csi-provider ``` Create a values file for Helm to use ``` cat << EOF > values.yaml global: openshift: true csi: enabled: true daemonSet: providersDir: /var/run/secrets-store-csi-providers agent: image: repository: "registry.connect.redhat.com/hashicorp/vault" tag: "1.20.4-ubi" injector: enabled: false server: image: repository: "registry.connect.redhat.com/hashicorp/vault" tag: "1.20.4-ubi" dev: enabled: true EOF ``` Install Hashicorp Vault with CSI enabled ``` helm install vault hashicorp/vault --namespace hashicorp-vault --values=values.yaml ``` ## Configure Hashicorp Vault 1. Get a bash prompt inside the Vault pod ``` oc exec -it vault-0 -- bash ``` 2. Create a Secret in Vault ``` vault kv put secret/db-pass password="hunter2" ``` 3. Configure Vault to use Kubernetes Auth ``` vault auth enable kubernetes ``` 4. Check your Cluster’s token issuer in another terminal ``` oc get authentication.config cluster \ -o json | jq -r .spec.serviceAccountIssuer ``` 5. Configure Kubernetes auth method If the issuer here does not match the above, update it. ``` vault write auth/kubernetes/config \ issuer="https://kubernetes.default.svc.cluster.local" \ token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \ kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt ``` **If your token issuer is empty** ``` [quickcluster@upi-0 ~]$ oc get authentication.config cluster \ > -o json | jq -r .spec.serviceAccountIssuer [quickcluster@upi-0 ~]$ ``` ``` vault write auth/kubernetes/config \ disable_iss_validation=true \ token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \ kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt ``` 6. Create a policy for our app ``` vault policy write internal-app - <<EOF path "secret/data/db-pass" { capabilities = ["read"] } EOF ``` 7. Create an auth role to access it ``` vault write auth/kubernetes/role/database \ bound_service_account_names=webapp-sa \ bound_service_account_namespaces=default \ policies=internal-app \ ttl=20m ``` 8. exit from the vault-0 pod ``` exit ``` ## Deploy a sample application 1. Create a SecretProviderClass in the default namespace ``` cat <<EOF | oc apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 kind: SecretProviderClass metadata: name: vault-database namespace: default spec: provider: vault parameters: vaultAddress: "http://vault.hashicorp-vault:8200" roleName: "database" objects: | - objectName: "db-password" secretPath: "secret/data/db-pass" secretKey: "password" EOF ``` 2. Create a service account webapp-sa ``` oc create serviceaccount -n default webapp-sa ``` 3. Create a Pod to use the secret ``` cat << EOF | oc apply -f - kind: Pod apiVersion: v1 metadata: name: webapp namespace: default spec: serviceAccountName: webapp-sa containers: - image: quay.io/rhn_support_jaliang/app:0.0.1 name: webapp volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "vault-database" EOF ``` 4. Check the Pod has the secret ``` oc -n default exec webapp \ -- cat /mnt/secrets-store/db-password ``` The output should match ``` hunter2 ``` ## Test case 2 ``` oc new-project vault-demo ``` ```bash= cat << 'EOF' | oc apply -f - apiVersion: v1 kind: Secret metadata: name: my-password-secret namespace: vault-demo type: Opaque stringData: db-password: "my-super-secret-password-from-k8s-secret" EOF ``` ```bash= cat << 'EOF' | oc apply -f - apiVersion: v1 kind: Pod metadata: name: echo-password-pod namespace: vault-demo spec: containers: - name: echo-container image: quay.io/quay/busybox:latest command: ["/bin/sh", "-c"] args: - "export SECRET_PASSWORD=$(cat /mnt/secrets-store/db-password) && echo \"Password from secret is: $SECRET_PASSWORD\" && sleep 3600" volumeMounts: - name: secret-volume mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secret-volume secret: secretName: my-password-secret restartPolicy: Never EOF ``` ```bash= oc exec -n hashicorp-vault -it vault-0 -- bash vault kv put secret/db-pass password-for-demo="my-super-secret-password-from-vault" vault write auth/kubernetes/role/database \ bound_service_account_names=default \ bound_service_account_namespaces=vault-demo \ policies=internal-app \ ttl=20m exit ``` ```bash= cat << 'EOF' | oc apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 kind: SecretProviderClass metadata: name: vault-database-demo namespace: vault-demo spec: provider: vault parameters: vaultAddress: "http://vault.hashicorp-vault:8200" roleName: "database" objects: | - objectName: "db-password" secretPath: "secret/data/db-pass" secretKey: "password-for-demo" EOF ``` ```bash= cat << 'EOF' | oc apply -f - apiVersion: v1 kind: Pod metadata: name: echo-password-pod-from-vault namespace: vault-demo spec: containers: - name: echo-container image: quay.io/quay/busybox:latest command: ["/bin/sh", "-c"] args: - "export SECRET_PASSWORD=$(cat /mnt/secrets-store/db-password) && echo \"Password from secret is: $SECRET_PASSWORD\" && sleep 3600" volumeMounts: - name: secrets-store-volume mountPath: "/mnt/secrets-store/" readOnly: true volumes: - name: secrets-store-volume csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "vault-database-demo" restartPolicy: Never EOF ``` ## Uninstall HashiCorp Vault with CSI driver enabled Delete the pod and ``` oc delete -n default pod webapp oc delete -n default secretproviderclass vault-database oc delete -n default serviceaccount webapp-sa ``` Delete the Hashicorp Vault Helm ``` helm delete -n hashicorp-vault vault ``` Delete the SCC for Hashicorp Vault ``` oc adm policy remove-scc-from-user privileged \ system:serviceaccount:hashicorp-vault:vault-csi-provider ``` Delete the Hashicorp vault project ``` oc delete project hashicorp-vault ``` ## Uninstalling the Kubernetes Secret Store CSI Delete the secrets store csi driver ``` helm delete -n k8s-secrets-store-csi csi-secrets-store ``` Delete the SecurityContextConstraints ``` oc adm policy remove-scc-from-user privileged \ system:serviceaccount:k8s-secrets-store-csi:secrets-store-csi-driver ``` ## Resources https://balakrishnan-b.medium.com/using-hashicorp-vault-provider-for-secrets-store-csi-driver-on-openshift-ec94f0a16e5 https://medium.com/pareture/hashicorp-kubernetes-vault-auth-claim-iss-is-invalid-abdd748c8ad6 https://cloud.redhat.com/experts/misc/secrets-store-csi/hashicorp-vault/