Skip to content
This repository has been archived by the owner on Aug 18, 2024. It is now read-only.
/ go-getter-app Public archive

A go app that can talk to backend vault and fetch data.

Notifications You must be signed in to change notification settings

govindkailas/go-getter-app

Repository files navigation

go-getter-app

Docker Build

The go-getter-app is a simple go microservice that exposes two API endpoints to read and write to VAULT

For the sake of clarity and easiness, let's deploy everything on Kubernetes. If you dont have K8s cluster, create one locally using microk8s

Create a namespace for vault

k create ns vault 

Add the HashiCorp Helm repository

helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update

Deploy the vault helm chart

helm install vault hashicorp/vault --set "server.dev.enabled=true" --namespace vault

This will bring up the vault in dev mode and it's not recommended for production use. If you would like to do a production-grade deployment, check this

Check the status of helm deployment

kubectl get all -n vault

You should see the vault pod in Running state + the vault service if the deployment was successful.

NAME                                        READY   STATUS    RESTARTS   AGE
pod/vault-agent-injector-7f7f68d457-2dtgp   1/1     Running   0          44s
pod/vault-0                                 1/1     Running   0          44s

NAME                               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
service/vault-internal             ClusterIP   None             <none>        8200/TCP,8201/TCP   44s
service/vault-agent-injector-svc   ClusterIP   10.152.183.224   <none>        443/TCP             44s
service/vault                      ClusterIP   10.152.183.65    <none>        8200/TCP,8201/TCP   44s

NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/vault-agent-injector   1/1     1            1           44s

NAME                                              DESIRED   CURRENT   READY   AGE
replicaset.apps/vault-agent-injector-7f7f68d457   1         1         1       44s

NAME                     READY   AGE
statefulset.apps/vault   1/1     44s

Now that we have vault ready, let's write some secrets

kubectl -n vault  exec -it vault-0 -- vault secrets enable -version=2 -path="go-app" kv
kubectl -n vault  exec -it vault-0 -- vault kv put go-app/user01 appaname="go-getter-app" password="My_Secure_Password" 

If vault cli is throwing permission denied, you might want to do vault login with the token.

You should see an output similar to this, take note of the secret path mentioned! We will need this later

===== Secret Path =====
secret/data/apps/config

======= Metadata =======
Key                Value
---                -----
created_time       2023-12-13T00:05:03.193794332Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

We must create a policy in vault to allow read/write operations from/to the secret path. We will be using the same secret path from the last result. Exec to the vault pod as there are multi-line commands to run and it may be error-prone if run from outside

kubectl -n vault  exec -it vault-0 -- sh

# After landing into the vault pod run the below,

vault policy write go-app-rw-policy - <<EOH
path "go-app/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
EOH

You would see Success! Uploaded policy: go-app-rw-policy, if the policy writes were successful. You can now exit from the pod.

The next step is to enable kubernetes auth in vault

kubectl -n vault  exec -it vault-0 -- vault auth enable kubernetes
# now lets list the auths, kubernetes should be there
kubectl -n vault  exec -it vault-0 -- vault auth list

Now, we have to allow vault to communicate to K8s cluster using the /config endpoint using the token issued by the service account More details here

kubectl -n vault  exec -it vault-0 -- sh
# After landing into the vault pod run the below,
vault write auth/kubernetes/config 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 issuer="kubernetes/serviceaccount"

⚠️ Note that it's important to mention issuer="kubernetes/serviceaccount" otherwise vault will reject the access as it will not know the token issuer. The issuer might be different if you are on a cloud provider k8s.

The next step will be creating namespace and service account for deploying the go-getter-app which would talk to vault and fetch the secrets.

kubectl create ns go-app
kubectl -n go-app create serviceaccount go-app-vault-auth-sa

Let's bind it all together 😀

vault write auth/kubernetes/role/go-app-role \
        bound_service_account_names=go-app-vault-auth-sa \
        bound_service_account_namespaces=go-app \
        policies=go-app-rw-policy \
        ttl=72h

How do we test if the vault role binding works as expected? If you are confident enough, go ahead and deploy the app kubectl apply -f go-getter-app.yaml and it should be able to fetch secrets from the vault using the auth methods we configured.

But if you want to see pod and vault communicate with each other, create a simple pod in the go-app namespace with the service account and check if it can read secrets from Vault:

apiVersion: v1
kind: Pod
metadata:
  name: vault-client
  namespace: go-app
spec:
  containers:
  - image: nginx:latest
    name: nginx
  serviceAccountName: go-app-vault-auth-sa

Save the above manifest as vault-client.yaml and run kubectl apply -f vault-client.yaml Once the pod is running, exec into it:

kubectl -n go-app exec -it vault-client -- bash
apt update && apt install -y jq
VAULT_ADDR=http://vault.vault:8200 # <vault service name>.<namespace>:<port>
jwt_token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) #get the service account token which is mounted to the pod
curl --request POST \
    --data '{"jwt": "'$jwt_token'", "role": "go-app-role"}' \
    ${VAULT_ADDR}/v1/auth/kubernetes/login | jq  # Check if we are getting the expected result with the client token
access_token=$(curl -s --request POST --data '{"jwt": "'$jwt_token'", "role": "go-app-role"}' ${VAULT_ADDR}/v1/auth/kubernetes/login | jq -r '.auth.client_token')
curl -H "X-Vault-Token: $access_token" -H "X-Vault-Namespace: vault" -X GET ${VAULT_ADDR}/v1/go-app/data/user01
## The result below shows the secret is retrieved successfully from vault
{"request_id":"3f80cc09-48c0-ad3f-ee3d-43d966e80c67","lease_id":"","renewable":false,"lease_duration":0,"data":{"data":{"appaname":"go-getter-app","password":"My_Secure_Password"},"metadata":{"created_time":"2023-12-13T06:03:04.584728825Z","custom_metadata":null,"deletion_time":"","destroyed":false,"version":4}},"wrap_info":null,"warnings":null,"auth":null}

Now that we have confirmed the vault role binding works, let's deploy the go-getter-app:

kubectl apply -f go-getter-app.yaml

References: