Initial idea was to use vault for secret management, but it was too complicated for this simple home setup and also creates chicken and egg situation, saas secret manager was chosen instead and vault documentation steps moved to separate file for archival purposes, if I decide to go back to it at some point.
Prepping hashicorp vault | doc
-
monitor argocd until
vault
application is deployed except forvault-0
pod (is should berunning
, but in 0/1 ready state)~$ kubectl get pods -n vault NAME READY STATUS RESTARTS AGE vault-agent-injector-59b9c84fd8-mzzj8 1/1 Running 0 43m vault-0 0/1 Running 0 28m
-
initialize vault-0 with one key share and one key threshold (for simplity sake, not secure)
$ kubectl exec vault-0 -- vault operator init \ -key-shares=1 \ -key-threshold=1 \ -format=json > cluster-keys.json
-
display unseal key found in
cluster-jeys.json
jq -r ".unseal_keys_b64[]" cluster-keys.json rrUtT32GztRy/pVWmcH0ZQLCCXon/TxCgi40FL1Zzus=
-
save the key into variable so it is not in shell history
VAULT_UNSEAL_KEY=$(jq -r ".unseal_keys_b64[]" cluster-keys.json)
-
unseal the vault on
vault-0
podkubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
-
display the root token found in
cluster-keys.json
$ jq -r ".root_token" cluster-keys.json hvs.HJmsajgGlWPTx6YNHoUljuOO
-
start interactive shell session on tthe
vault-0
pod$ kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh / $
-
login with the root token
$ vault login Token (will be hidden): Success! You are now authenticated. The token information displayed below is already stored in the token helper. You do NOT need to run "vault login" again. Future Vault requests will automatically use this token. Key Value --- ----- token hvs.HJmsajgGlWPTx6YNHoUljuOO token_accessor JVsMJHVu6rTWbPLlYmWQTq1R token_duration ∞ token_renewable false token_policies ["root"] identity_policies [] policies ["root"]
-
enable an instance of the kv-v2 secrets engine at the path
secret
$ vault secrets enable -path=secret kv-v2 Success! Enabled the kv-v2 secrets engine at: secret/
-
create secrets for applications
vault put secret/cert-manager/letsencrypt-issuer [email protected]
-
verify secret got created
/ $ vault kv get secret/cert-manager/letsencrypt-issuer =============== Secret Path =============== secret/data/cert-manager/letsencrypt-issuer ======= Metadata ======= Key Value --- ----- created_time 2023-01-29T19:31:27.783982045Z custom_metadata <nil> deletion_time n/a destroyed false version 1 ==== Data ==== Key Value --- ----- email [email protected]
-
enable kubernetes authentication method
$ vault auth enable kubernetes Success! Enabled kubernetes auth method at: kubernetes/
-
configure the Kubernetes authentication method to use the location of the Kubernetes API
$ vault write auth/kubernetes/config \ kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:$KUBERNETES_SERVICE_PORT" Success! Data written to: auth/kubernetes/config
-
create admin policy (overkill, actual policy should only provide whats needed)
$ vault policy write admin - <<EOF # Read system health check path "sys/health" { capabilities = ["read", "sudo"] } # Create and manage ACL policies broadly across Vault # List existing policies path "sys/policies/acl" { capabilities = ["list"] } # Create and manage ACL policies path "sys/policies/acl/*" { capabilities = ["create", "read", "update", "delete", "list", "sudo"] } # Enable and manage authentication methods broadly across Vault # Manage auth methods broadly across Vault path "auth/*" { capabilities = ["create", "read", "update", "delete", "list", "sudo"] } # Create, update, and delete auth methods path "sys/auth/*" { capabilities = ["create", "update", "delete", "sudo"] } # List auth methods path "sys/auth" { capabilities = ["read"] } # Enable and manage the key/value secrets engine at `secret/` path # List, create, update, and delete key/value secrets path "secret/*" { capabilities = ["create", "read", "update", "delete", "list", "sudo"] } # Manage secrets engines path "sys/mounts/*" { capabilities = ["create", "read", "update", "delete", "list", "sudo"] } # List existing secrets engines. path "sys/mounts" { capabilities = ["read"] } EOF Success! Uploaded policy: read-secrets
-
create authentication role named
read-secrets
that connects the Kubernetes service accounts andread-secrets
policy and allows listed namespaces to access this role$ vault write auth/kubernetes/role/external-secrets \ bound_service_account_names="*" \ bound_service_account_namespaces="*" \ policies=admin \ ttl=1h Success! Data written to: auth/kubernetes/role/read-secrets
Akeyless setup for external-secrets - WebUI method (todo: document an api way of doing this as preferred method)
-
register account for Akeyless account (free for 5 clients and 2000 static secrets)
-
create Auth Method
- New API Key
- Name
external-secrets
- Location
/
- Allowed Client IPs
<external_ip_of_k8s>/32
- Save
- Save to .CSV file
- take note where the file is saved, we will use it later
akeyless_creds.csv
-
create Access Role
- Name
external-secrets-reader
- Location
/
- Create Role
- Method ➕ Associate
- Auth Method
/external-secrets
- Auth Method
- Access Path ➕ Add
- Allow acces to the following path
/k8s-at-home/*
- Apply recursively
- Allow the following operations:
- Create
- Read
- Update
- Delete
- List
- Deny
- Allow acces to the following path
- Name
-
create Secrets & Keys
- ➕ New Static Secret
- Name
letsencrypt-email
- Location
/k8s-at-home
- Value
<[email protected]>
- Name
- ➕ New Static Secret
-
copy saved Akeyless creds, secret template and powershell script to the same directory somewhere outside git repo
cp </replace-with-path-to/>akeyless_creds.csv ~ cp ~/k8s-at-home/src/akeyless-secret.* ~
-
run pwsh script
$ pwsh PS> ./akeyless-secret.ps1 Updated 'akeyless-secret.yaml' with values from 'akeyless_creds.csv'. PS> exit
-
apply secret
$ kubectl apply -f ./akeyless-secret.yaml -n external-secrets secret/akeyless-creds created
-
create cloudflare account
-
➕ Add Site (free plan)
-
"Review your DNS records" - scroll down and click Continue
-
take note of cloudflare's name servers listed in step 4
-
login to your DNS provider and configure cloudflare dns servers for you domain
-
finish DNS config on cloudflare side - Done, check nameservers
-
at "Quick Start Guide" click
Finish later
-
at "Overview" click on Check nameservers once more
-
wait until nameserver config is verified (will receive an email confirming it)
-
on the side panel navigate to "Zero Trust"
-
in zero trust page navigate to Access->Tunnels
-
progress through Complete setup - choose free plan (will require adding payment method, but you won't be charged)
-
complete purchase of the free plan for 0 dollars.
-
download cloudflared binary
wget -O cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
-
make it executable and login
sudo chmod +x cloudlfared ./cloudflared login
-
click on provided link and login, in the browser click on your cloudflare "site" and Authorize it
-
create your tunnel
$ ./cloudflared tunnel create my_tunnel --- Tunnel credentials written to /home/<user>/.cloudflared/ef824aef-7557-4b41-a398-4684585177ad.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel. Created tunnel my_tunnel with id ef824aef-7557-4b41-a398-4684585177ad
-
create doppler secret
CLOUDFLARE_CREDENTIALS_JSON
:<contents of ef824aef-7557-4b41-a398-4684585177ad.json>
Route internet traffic to cloudflared | doc
-
Go to the Cloudflare dashboard.
-
Navigate to the DNS tab.
-
Now create a CNAMEs targeting .cfargotunnel.com. In this example, the tunnel ID is ef824aef-7557-4b41-a398-4684585177ad, so create a CNAME record specifically targeting ef824aef-7557-4b41-a398-4684585177ad.cfargotunnel.com.