Skip to content

Instantly share code, notes, and snippets.

@kawsark
Last active December 20, 2023 12:50
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kawsark/bb533eb25724e78b708cdcc02bc05e9e to your computer and use it in GitHub Desktop.
Save kawsark/bb533eb25724e78b708cdcc02bc05e9e to your computer and use it in GitHub Desktop.
Vault Agent with PKI certificate rendering
### Configure variables
These variables will be used for this snippet. Please substitute accordingly.
```bash
export RootCAName="root_ca"
export InterCAName="inter_ca"
export CommonName="hashidemos.io"
export InterCommonName="inter.hashidemos.io"
export Root_CA_ttl="730h"
export Inter_CA_ttl="350h"
export Cert_ttl="8h"
```
### PKI Secrets engine setup
```bash
## Go to working directory
mkdir -p /tmp/certs && cd /tmp/certs
# Mount Root CA and generate certs:
vault secrets disable ${RootCAName}
vault secrets enable -path ${RootCAName} pki
vault secrets tune -max-lease-ttl=${Root_CA_ttl} ${RootCAName}
# Generate Root key and certs
vault write -format=json ${RootCAName}/root/generate/internal \
common_name="${CommonName}" ttl=${Inter_CA_ttl} | tee \
>(jq -r .data.certificate > /tmp/certs/ca.pem) \
>(jq -r .data.issuing_ca > /tmp/certs/issuing_ca.pem)
# Mount Intermediate CA and generate CSR:
vault secrets disable ${InterCAName}
vault secrets enable -path ${InterCAName} pki
vault secrets tune -max-lease-ttl=${Inter_CA_ttl} ${InterCAName}
vault write -format=json ${InterCAName}/intermediate/generate/internal \
common_name="${CommonName}" ttl=${Inter_CA_ttl} | tee \
>(jq -r .data.csr > /tmp/certs/${InterCAName}.csr)
vault write -format=json ${RootCAName}/root/sign-intermediate \
csr=@/tmp/certs/${InterCAName}.csr \
common_name="${CommonName}" ttl=${CA_ttl} | tee \
>(jq -r .data.certificate > /tmp/certs/${InterCAName}.pem) \
>(jq -r .data.issuing_ca > /tmp/certs/${InterCAName}_issuing_ca.pem)
vault write ${InterCAName}/intermediate/set-signed certificate=@/tmp/certs/${InterCAName}.pem
# Write URLs
vault write ${InterCAName}/config/urls \
issuing_certificates="http://127.0.0.1:8200/v1/${InterCAName}/ca" \
crl_distribution_points="http://127.0.0.1:8200/v1/${InterCAName}/crl" \
ocsp_servers="http://127.0.0.1:8200/v1/${InterCAName}/ocsp"
# Generate certificate for dev.hashidemos.io domain:
role_name=app1
prefix=dev
vault write ${InterCAName}/roles/${role_name} \
allowed_domains="${prefix}.${CommonName}" \
allow_subdomains="true" \
max_ttl=${Cert_ttl} \
generate_lease=true
# Verify
vault read ${InterCAName}/roles/${role_name}
## Test
# Generate a certificate with lease
vault write ${InterCAName}/issue/${role_name} common_name=app1.${prefix}.${CommonName}
# Generate a certificate with no lease
vault write ${InterCAName}/roles/${role_name}-no-lease \
allowed_domains="${prefix}.${CommonName}" \
allow_subdomains="true" \
max_ttl=${Cert_ttl}
vault write ${InterCAName}/issue/${role_name}-no-lease common_name=app1.${prefix}.${CommonName}
```
### AppRole and Vault Agent configuration
```bash
## Setup AppRole and policy
mkdir -p /tmp/certs
cat <<EOF > /tmp/certs/cert.policy
path "${InterCAName}/issue*" {
capabilities = ["create","update"]
}
path "auth/token/renew" {
capabilities = ["update"]
}
path "auth/token/renew-self" {
capabilities = ["update"]
}
EOF
vault policy write cert-policy /tmp/certs/cert.policy
vault token create -policy=cert-policy
vault auth enable approle
vault write auth/approle/role/cert-role token_policies="cert-policy" secret_id_ttl=24h token_ttl=5m token_max_ttl=4h
vault read -format=json auth/approle/role/cert-role/role-id > role.json
vault write -format=json -f auth/approle/role/cert-role/secret-id > secretid.json
export ROLE_ID="$(cat role.json | jq -r .data.role_id )" && echo $ROLE_ID | tee roleid
export SECRET_ID="$(cat secretid.json | jq -r .data.secret_id )" && echo $SECRET_ID |tee secretid
## Test
export VAULT_TOKEN=$(vault write -format=json auth/approle/login role_id=$ROLE_ID secret_id=$SECRET_ID | jq -r .auth.client_token)
vault write -format=json ${InterCAName}/issue/${role_name} \
common_name=app1.${prefix}.${CommonName} ttl=5m
## Write template files
# https://github.com/hashicorp/vault-k8s/issues/21
cat <<TPL > dynamic-cert.tpl
{{ with secret "${InterCAName}/issue/${role_name}" "common_name=nginx.${prefix}.${CommonName}" "ttl=5m" }}
{{ .Data.certificate }}
{{ end }}
TPL
## Vault Agent with a source and destination
cat <<EOF > vault-agent.hcl
pid_file = "./pidfile"
vault {
address = "http://127.0.0.1:8200"
}
auto_auth {
method {
type = "approle"
config = {
role_id_file_path = "/tmp/certs/roleid"
secret_id_file_path = "/tmp/certs/secretid"
}
}
sink {
type = "file"
config = {
path = "/tmp/certs/token"
}
}
}
template {
source = "/tmp/certs/dynamic-cert.tpl"
destination = "/tmp/certs/app-certs.txt"
}
EOF
vault agent -log-level debug -config=./vault-agent.hcl
## Vault Agent with contents
cat <<EOF > vault-agent-contents.hcl
pid_file = "./pidfile"
vault {
address = "http://127.0.0.1:8200"
}
auto_auth {
method {
type = "approle"
config = {
role_id_file_path = "/tmp/certs/roleid"
secret_id_file_path = "/tmp/certs/secretid"
}
}
sink {
type = "file"
config = {
path = "/tmp/certs/token"
}
}
}
# TLS SERVER CERTIFICATE
template {
contents = "{{ with secret \"${InterCAName}/issue/${role_name}\" \"common_name=nginx.${prefix}.${CommonName}\" \"ttl=1m\" }}{{ .Data.certificate }}{{ end }}"
destination = "/tmp/certs/nginx.${prefix}.${CommonName}.crt"
}
# TLS PRIVATE KEY
template {
contents = "{{ with secret \"${InterCAName}/issue/${role_name}\" \"common_name=nginx.${prefix}.${CommonName}\" \"ttl=1m\" }} {{ .Data.private_key }}{{ end }}"
destination = "/tmp/certs/nginx.${prefix}.${CommonName}.key"
}
# TLS CA CERTIFICATE
template {
contents = "{{ with secret \"${InterCAName}/issue/${role_name}\" \"common_name=nginx.${prefix}.${CommonName}\" \"ttl=1m\" }} {{ .Data.issuing_ca }}{{ end }}"
destination = "/tmp/certs/ca.crt"
}
EOF
vault agent -log-level debug -config=./vault-agent-contents.hcl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment