init
This commit is contained in:
15
.gitlab-ci.yml
Normal file
15
.gitlab-ci.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
read_secrets:
|
||||||
|
script:
|
||||||
|
# Check job's ref name
|
||||||
|
- echo $CI_COMMIT_REF_NAME
|
||||||
|
# and is this ref protected
|
||||||
|
- echo $CI_COMMIT_REF_PROTECTED
|
||||||
|
# Vault's address can be provided here or as CI/CD variable
|
||||||
|
- export VAULT_ADDR=https://vault.ducoterra.net
|
||||||
|
# Authenticate and get token. Token expiry time and other properties can be configured
|
||||||
|
# when configuring JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1
|
||||||
|
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT)"
|
||||||
|
# Now use the VAULT_TOKEN to read the secret and store it in environment variable
|
||||||
|
- export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"
|
||||||
|
# Use the secret
|
||||||
|
- echo $PASSWORD
|
||||||
198
README.md
Normal file
198
README.md
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
# Vault
|
||||||
|
|
||||||
|
## Prereqs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew tap hashicorp/tap
|
||||||
|
brew install hashicorp/tap/vault
|
||||||
|
|
||||||
|
brew install jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install (Standalone)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f certificate.yaml
|
||||||
|
|
||||||
|
helm repo add hashicorp https://helm.releases.hashicorp.com
|
||||||
|
helm search repo hashicorp/vault
|
||||||
|
helm upgrade --install vault hashicorp/vault --values values.yaml
|
||||||
|
|
||||||
|
mkdir ~/.vault-keys
|
||||||
|
kubectl exec -ti vault-0 -- vault operator init -key-shares=5 -key-threshold=3 -format=json > ~/.vault-keys/cluster-keys.json
|
||||||
|
kubectl exec -ti vault-0 -- vault operator unseal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install (Cluster)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f certificate.yaml
|
||||||
|
|
||||||
|
helm repo add hashicorp https://helm.releases.hashicorp.com
|
||||||
|
helm search repo hashicorp/vault
|
||||||
|
helm upgrade --install vault hashicorp/vault --values values.yaml
|
||||||
|
|
||||||
|
mkdir ~/.vault-keys
|
||||||
|
kubectl exec -ti vault-0 -- vault operator init -key-shares=5 -key-threshold=3 -format=json > ~/.vault-keys/cluster-keys.json
|
||||||
|
kubectl exec -ti vault-0 -- vault operator unseal
|
||||||
|
|
||||||
|
kubectl exec -ti vault-1 -- vault operator raft join http://vault-0.vault-internal:8200
|
||||||
|
kubectl exec -ti vault-1 -- vault operator unseal
|
||||||
|
|
||||||
|
kubectl exec -ti vault-2 -- vault operator raft join http://vault-0.vault-internal:8200
|
||||||
|
kubectl exec -ti vault-2 -- vault operator unseal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add policy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vault policy write ducoterra policies/ducoterra.hcl
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add user
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vault auth enable userpass
|
||||||
|
vault write auth/userpass/users/ducoterra \
|
||||||
|
policies=ducoterra \
|
||||||
|
password=password
|
||||||
|
```
|
||||||
|
|
||||||
|
## Enable KV Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vault secrets enable -path=secret kv-v2
|
||||||
|
|
||||||
|
vault kv put secret/okta username='static-user' password='static-password'
|
||||||
|
vault kv get secret/okta
|
||||||
|
```
|
||||||
|
|
||||||
|
## TOTP
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vault secrets enable totp
|
||||||
|
|
||||||
|
vault write totp/keys/okta \
|
||||||
|
url="otpauth://totp/Vault:test@test.com?secret=SECRET&issuer=Vault"
|
||||||
|
|
||||||
|
vault read totp/code/okta
|
||||||
|
```
|
||||||
|
|
||||||
|
Policy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
path "totp/keys/*" {
|
||||||
|
capabilities = ["update"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "totp/code/*" {
|
||||||
|
capabilities = ["read"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kubernetes Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl exec -it vault-0 -- /bin/sh
|
||||||
|
|
||||||
|
vault login -method=token <token>
|
||||||
|
vault auth enable kubernetes
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
vault policy write internal-app - <<EOF
|
||||||
|
path "internal/data/database/config" {
|
||||||
|
capabilities = ["read"]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
vault write auth/kubernetes/role/internal-app \
|
||||||
|
bound_service_account_names=internal-app \
|
||||||
|
bound_service_account_namespaces=gitlab \
|
||||||
|
policies=internal-app \
|
||||||
|
ttl=24h
|
||||||
|
|
||||||
|
rm /home/vault/.vault-token
|
||||||
|
```
|
||||||
|
|
||||||
|
Set your kube config to the namespace you want to use vault with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f service-account-internal-app.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Add secrets to your pod
|
||||||
|
|
||||||
|
```bash
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
vault.hashicorp.com/agent-inject: "true"
|
||||||
|
vault.hashicorp.com/role: "internal-app"
|
||||||
|
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gitlab Integration
|
||||||
|
|
||||||
|
### Enable JWT auth for Gitlab
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable jwt auth
|
||||||
|
vault auth enable jwt
|
||||||
|
|
||||||
|
# Create a policy
|
||||||
|
vault policy write myproject-production - <<EOF
|
||||||
|
# Policy name: myproject-production
|
||||||
|
#
|
||||||
|
# Read-only permission on 'secret/data/myproject/production/*' path
|
||||||
|
path "secret/data/myproject/production/*" {
|
||||||
|
capabilities = [ "read" ]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create a role
|
||||||
|
vault write auth/jwt/role/myproject-production - <<EOF
|
||||||
|
{
|
||||||
|
"role_type": "jwt",
|
||||||
|
"policies": ["myproject-production"],
|
||||||
|
"token_explicit_max_ttl": 60,
|
||||||
|
"user_claim": "user_email",
|
||||||
|
"bound_claims_type": "glob",
|
||||||
|
"bound_claims": {
|
||||||
|
"project_id": "22",
|
||||||
|
"ref_protected": "true",
|
||||||
|
"ref_type": "branch",
|
||||||
|
"ref": "auto-deploy-*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Write the auth method
|
||||||
|
vault write auth/jwt/config \
|
||||||
|
jwks_url="https://gitlab.ducoterra.net/-/jwks" \
|
||||||
|
bound_issuer="gitlab.ducoterra.net"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pipeline syntax
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
read_secrets:
|
||||||
|
script:
|
||||||
|
# Check job's ref name
|
||||||
|
- echo $CI_COMMIT_REF_NAME
|
||||||
|
# and is this ref protected
|
||||||
|
- echo $CI_COMMIT_REF_PROTECTED
|
||||||
|
# Vault's address can be provided here or as CI/CD variable
|
||||||
|
- export VAULT_ADDR=https://vault.ducoterra.net
|
||||||
|
# Authenticate and get token. Token expiry time and other properties can be configured
|
||||||
|
# when configuring JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1
|
||||||
|
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT)"
|
||||||
|
# Now use the VAULT_TOKEN to read the secret and store it in environment variable
|
||||||
|
- export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"
|
||||||
|
# Use the secret
|
||||||
|
- echo $PASSWORD
|
||||||
|
```
|
||||||
12
certificate.yaml
Normal file
12
certificate.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: vault.ducoterra.net
|
||||||
|
spec:
|
||||||
|
secretName: vault-tls-cert
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
||||||
|
commonName: vault.ducoterra.net
|
||||||
|
dnsNames:
|
||||||
|
- vault.ducoterra.net
|
||||||
11
policies/ducoterra.hcl
Normal file
11
policies/ducoterra.hcl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
path "totp/keys/*" {
|
||||||
|
capabilities = ["update"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "totp/code/*" {
|
||||||
|
capabilities = ["read"]
|
||||||
|
}
|
||||||
|
|
||||||
|
path "secret/*" {
|
||||||
|
capabilities = ["create", "read", "update", "delete", "list"]
|
||||||
|
}
|
||||||
29
scripts/vault_unseal.py
Executable file
29
scripts/vault_unseal.py
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
|
||||||
|
vaults = ["vault-0"]
|
||||||
|
|
||||||
|
home = os.getenv("HOME")
|
||||||
|
with open(os.path.join(home, ".vault-keys/cluster-keys.json")) as f:
|
||||||
|
vault_secrets = json.load(f)
|
||||||
|
|
||||||
|
procs = []
|
||||||
|
|
||||||
|
for vault in vaults:
|
||||||
|
procs += [
|
||||||
|
threading.Thread(
|
||||||
|
target = subprocess.run,
|
||||||
|
args = (
|
||||||
|
["kubectl", "exec", "-ti", vault, "--", "vault", "operator", "unseal", vault_secrets.get("unseal_keys_b64")[key]],))
|
||||||
|
for key in range(int(vault_secrets.get("unseal_threshold")))
|
||||||
|
]
|
||||||
|
|
||||||
|
for thread in procs:
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
for thread in procs:
|
||||||
|
thread.join()
|
||||||
4
service-account-internal.yaml
Normal file
4
service-account-internal.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: internal-app
|
||||||
1
setenv.sh
Executable file
1
setenv.sh
Executable file
@@ -0,0 +1 @@
|
|||||||
|
kubectl config set current-context k3os-alpha.dnet-admin-vault
|
||||||
60
values.yaml
Normal file
60
values.yaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
global:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
server:
|
||||||
|
# ha:
|
||||||
|
# enabled: true
|
||||||
|
# config: |
|
||||||
|
# ui = true
|
||||||
|
|
||||||
|
# listener "tcp" {
|
||||||
|
# address = "[::]:8200"
|
||||||
|
# cluster_address = "[::]:8201"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# storage "file" {
|
||||||
|
# path = "/vault/data"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# raft:
|
||||||
|
# enabled: true
|
||||||
|
|
||||||
|
standalone:
|
||||||
|
enabled: true
|
||||||
|
config: |
|
||||||
|
ui = true
|
||||||
|
|
||||||
|
listener "tcp" {
|
||||||
|
tls_disable = 1
|
||||||
|
address = "[::]:8200"
|
||||||
|
cluster_address = "[::]:8201"
|
||||||
|
}
|
||||||
|
storage "file" {
|
||||||
|
path = "/vault/data"
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStorage:
|
||||||
|
enabled: true
|
||||||
|
size: 32Gi
|
||||||
|
storageClass: null
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
kubernetes.io/ingress.class: nginx
|
||||||
|
hosts:
|
||||||
|
- host: vault.ducoterra.net
|
||||||
|
paths:
|
||||||
|
- /
|
||||||
|
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- vault.ducoterra.net
|
||||||
|
secretName: vault-tls-cert
|
||||||
|
|
||||||
|
ui:
|
||||||
|
enabled: true
|
||||||
|
serviceType: ClusterIP
|
||||||
Reference in New Issue
Block a user