Add docs to README explaining how to enable and use aws auth and aws client secrets.
Vault
Prereqs
brew tap hashicorp/tap
brew install hashicorp/tap/vault
brew install jq
Install (bare metal)
-
Create a vault user
useradd --system --home /etc/vault.d --shell /bin/false vault -
Create a config file
mkdir -p /etc/vault.d touch /etc/vault.d/vault.hcl chmod 640 /etc/vault.d/vault.hcl chown --recursive vault:vault /etc/vault.d -
Add the following
storage "file" { path = "/vault/data" } listener "tcp" { address = "0.0.0.0:8200" tls_disable = 0 tls_cert_file = "/etc/ssl/certs/pi-vault.pem" tls_key_file = "/etc/vault.d/pi-vault.key" } ui = true -
Add your CA (if you have one) to /etc/ssl/certs and run
update-ca-certificates -
Create a vault storage location
mkdir -p /vault/data chown --recursive vault:vault /vault/data/ -
Allow vault to use mlock syscall to prevent memory from being swapped
setcap cap_ipc_lock=+ep /usr/local/bin/vault -
Create a systemd process
touch /etc/systemd/system/vault.service -
Add the following
[Unit] Description="HashiCorp Vault - A tool for managing secrets" Documentation=https://www.vaultproject.io/docs/ Requires=network-online.target After=network-online.target ConditionFileNotEmpty=/etc/vault.d/vault.hcl StartLimitIntervalSec=60 StartLimitBurst=3 [Service] User=vault Group=vault ProtectSystem=full ProtectHome=read-only PrivateTmp=yes PrivateDevices=yes SecureBits=keep-caps AmbientCapabilities=CAP_IPC_LOCK Capabilities=CAP_IPC_LOCK+ep CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK NoNewPrivileges=yes ExecStart=/usr/local/bin/vault server -config=/etc/vault.d/vault.hcl ExecReload=/bin/kill --signal HUP $MAINPID KillMode=process KillSignal=SIGINT Restart=on-failure RestartSec=5 TimeoutStopSec=30 StartLimitInterval=60 StartLimitIntervalSec=60 StartLimitBurst=3 LimitNOFILE=65536 LimitMEMLOCK=infinity [Install] WantedBy=multi-user.target EOF -
Start the service with
systemctl start vault -
Run
vault operator initon the server to generate keys -
Unseal the vault
-
Add the following backup job to /etc/crontab
0 0 * * * root tar czvf /vault/backups/$(date +\%y-\%m-\%d-\%H-\%M)-pivault.tar.gz /vault/data 0 0 * * * root find /vault/backups/* -mtime +7 -exec rm {} +
Install (Standalone)
kubectl apply -f k8s/certificate.yaml
helm repo add hashicorp https://helm.releases.hashicorp.com
helm search repo hashicorp/vault
helm upgrade --install vault hashicorp/vault --values helm/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)
This assumes you have an unseal vault available! See ha-test for manual unseal.
kubectl apply -f k8s/certificate.yaml
helm repo add hashicorp https://helm.releases.hashicorp.com
helm search repo hashicorp/vault
helm upgrade --install vault hashicorp/vault --values helm/ha.yaml
mkdir ~/.vault-keys
kubectl exec -ti vault-0 -- vault operator init -format=json > ~/.vault-keys/vault-cluster-keys.json
# Only run the unseal if not autounsealing
# 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/Update policy
vault policy write ducoterra policies/ducoterra.hcl
Add user
vault auth enable userpass
vault auth tune -default-lease-ttl=24h userpass
vault write auth/userpass/users/ducoterra \
policies=ducoterra \
password='<password>'
Enable KV Secrets
vault secrets enable -path=secret kv-v2
vault kv put secret/okta username='static-user' password='static-password'
vault kv get secret/okta
TOTP
vault secrets enable totp
vault write totp/keys/okta \
url='otpauth://totp/Vault:reese.wells@nimbisservices.com?secret=SECRET&issuer=Okta'
vault read totp/code/okta
Policy:
path "totp/keys/*" {
capabilities = ["update"]
}
path "totp/code/*" {
capabilities = ["read"]
}
Kubernetes Secrets
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
kubectl apply -f k8s/service-account-internal-app.yaml
Add secrets to your pod
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
# 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": "127",
"ref_protected": "false",
"ref_type": "branch",
"ref": "main"
}
}
EOF
# Write the auth method
vault write auth/jwt/config \
jwks_url="https://gitlab.ducoterra.net/-/jwks" \
bound_issuer="gitlab.ducoterra.net"
Pipeline syntax
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
Certificate Management
https://learn.hashicorp.com/tutorials/vault/pki-engine https://learn.hashicorp.com/tutorials/vault/kubernetes-cert-manager
Create a CA
export ROOT_PATH=dnet
# Note: 19800h is Apple's limit
vault secrets enable -path=$ROOT_PATH pki
vault secrets tune -max-lease-ttl=19800h $ROOT_PATH
# Create a root CA
vault write $ROOT_PATH/root/generate/internal \
common_name="Ducoterra Root CA" \
ttl=19800h
# Create a CA URL
vault write $ROOT_PATH/config/urls \
issuing_certificates="https://vault.ducoterra.net/v1/$ROOT_PATH/ca" \
crl_distribution_points="https://vault.ducoterra.net/v1/$ROOT_PATH/crl"
Navigate to https://vault.ducoterra.net/v1/$ROOT_PATH/ca and download the CA. Import to your devices.
Create an intermediate CA
export ROOT_PATH=dnet
export PKI_PATH=dnet_inter
vault secrets enable -path=$PKI_PATH pki
vault secrets tune -max-lease-ttl=9900h $PKI_PATH
# Create CSR to sign with root CA
vault write -format=json $PKI_PATH/intermediate/generate/internal \
common_name="Ducoterra Intermediate CA" \
| jq -r '.data.csr' > certs/$PKI_PATH.csr
# Sign the CSR with the root CA
vault write -format=json $ROOT_PATH/root/sign-intermediate \
csr=@certs/$PKI_PATH.csr format=pem_bundle ttl=9900h \
| jq -r '.data.certificate' > certs/$PKI_PATH.cert.pem
# Save the signed cert to vault
vault write $PKI_PATH/intermediate/set-signed certificate=@certs/$PKI_PATH.cert.pem
# Create a CA URL
vault write $PKI_PATH/config/urls \
issuing_certificates="https://vault.ducoterra.net/v1/$PKI_PATH/ca" \
crl_distribution_points="https://vault.ducoterra.net/v1/$PKI_PATH/crl"
Navigate to https://vault.ducoterra.net/v1/$PKI_PATH/ca and download the CA. Import to your devices.
Allow .dnet and .hole certificates
export PKI_PATH=dnet_inter
# Allow .dnet subdomain
vault write $PKI_PATH/roles/dnet \
allowed_domains=dnet \
allow_subdomains=true max_ttl=8760h
# Allow .hole subdomain
vault write $PKI_PATH/roles/pi_hole \
allowed_domains=hole \
allow_subdomains=true max_ttl=8760h
Issue a certificate
export PKI_PATH=dnet # or dnet_inter
export CNAME=freenas.dnet
# Use -format=json to dump a json file
vault write $PKI_PATH/issue/dnet \
common_name=$CNAME \
ttl=8760h > certs/$CNAME.cert
# Pihole Example
vault write $PKI_PATH/issue/pi_hole \
common_name=$CNAME \
ttl=8760h > certs/$CNAME.cert
Adding cert to freenas
Only caveat here is to paste the certificate and then the full chain cert below in the "certificate" section. iOS will infintely refresh the page if the full chain isn't provided.
Adding cert to pihole
# Install lighttpd-mod-openssl
apt install -y lighttpd-mod-openssl
# Paste the isser CA in here:
vim /etc/ssl/certs/vault-ca.pem
chown www-data /etc/ssl/certs/vault-ca.pem
chmod 770 /etc/ssl/certs/vault-ca.pem
# Paste the private key first, then the certificate in here:
vim /etc/ssl/certs/pihole.pem
chown www-data /etc/ssl/certs/pihole.pem
chmod 770 /etc/ssl/certs/pihole.pem
# Add the config below to /etc/lighttpd/external.conf
vim /etc/lighttpd/external.conf
$HTTP["host"] == "pi.hole" {
# Ensure the Pi-hole Block Page knows that this is not a blocked domain
setenv.add-environment = ("fqdn" => "true")
# Enable the SSL engine with a LE cert, only for this specific host
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/ssl/certs/pihole.pem"
ssl.ca-file = "/etc/ssl/certs/vault-ca.pem"
ssl.honor-cipher-order = "enable"
ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
}
# Redirect HTTP to HTTPS
$HTTP["scheme"] == "http" {
$HTTP["host"] =~ ".*" {
url.redirect = (".*" => "https://%0$0")
}
}
}
# Restart the service
service lighttpd restart
Adding cert to vault
# Paste the primary cert and then the issuer CA in here:
vim /etc/ssl/certs/vault-cert.pem
chown vault:vault /etc/ssl/certs/vault-cert.pem
chmod 770 /etc/ssl/certs/vault-cert.pem
# Paste the private key in here:
vim /etc/ssl/certs/vault-key.pem
chown vault:vault /etc/ssl/certs/vault-key.pem
chmod 770 /etc/ssl/certs/vault-key.pem
Edit /etc/vault.d/vault.hcl and add the following:
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 0
tls_cert_file = "/etc/ssl/certs/vault-cert.pem"
tls_key_file = "/etc/ssl/certs/vault-key.pem"
}
Run service vault restart
Adding cert to cloudkey
THIS DOESN'T WORK
service unifi stop
# Remove the UNIFI_SSL_KEYSTORE=/etc/ssl/private/unifi.keystore.jks line from config
cp /etc/default/unifi /etc/default/unifi.back
vim /etc/default/unifi
# Remove the keystore reference
mv /usr/lib/unifi/data/keystore /usr/lib/unifi/data/keystore.back
# Copy your primary SSL Certificate into /etc/ssl/private/cloudkey.crt
cp /etc/ssl/private/cloudkey.crt /etc/ssl/private/cloudkey.crt.back
vim /etc/ssl/private/cloudkey.crt
# Copy your private key into /etc/ssl/private/cloudkey.key
cp /etc/ssl/private/cloudkey.key /etc/ssl/private/cloudkey.key.back
vim /etc/ssl/private/cloudkey.key
# Add the CA to /etc/ssl/private/vault-ca.pem
vim /etc/ssl/private/vault-ca.pem
# Generate the key bundle
openssl pkcs12 -export -in /etc/ssl/private/cloudkey.crt -inkey \
/etc/ssl/private/cloudkey.key -out /etc/ssl/private/cloudkey.p12 \
-name unifi -CAfile /etc/ssl/private/vault-ca.pem -caname vault -password pass:temppass
# Import to keystore
# Default password is "aircontrolenterprise"
keytool -importkeystore -deststorepass aircontrolenterprise \
-destkeypass aircontrolenterprise -destkeystore /usr/lib/unifi/data/keystore \
-srckeystore /etc/ssl/private/cloudkey.p12 -srcstoretype PKCS12 -srcstorepass temppass -alias unifi -noprompt
service unifi start
Revoke a certificate
export PKI_PATH=dnet_inter
vault write $PKI_PATH/revoke serial_number=<serial_number>
vault write $PKI_PATH/tidy tidy_cert_store=true tidy_revoked_certs=true
Use with cert-manager
export PKI_PATH=dnet_inter
vault policy write $PKI_PATH - <<EOF
path "$PKI_PATH*" { capabilities = ["read", "list"] }
path "$PKI_PATH/roles/*" { capabilities = ["create", "update"] }
path "$PKI_PATH/sign/*" { capabilities = ["create", "update"] }
path "$PKI_PATH/issue/*" { capabilities = ["create"] }
EOF
vault write auth/kubernetes/role/issuer \
bound_service_account_names=issuer \
bound_service_account_namespaces=cert-manager \
policies=$PKI_PATH \
ttl=20m
kubectl -n cert-manager create serviceaccount issuer
ISSUER_SECRET_REF=$(kubectl -n cert-manager get serviceaccount issuer -o json | jq -r ".secrets[].name")
kubectl -n cert-manager apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: vault-issuer
spec:
vault:
server: https://vault.ducoterra.net
path: $PKI_PATH/sign/dnet
auth:
kubernetes:
mountPath: /v1/auth/kubernetes
role: issuer
secretRef:
name: $ISSUER_SECRET_REF
key: token
EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
# cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.org/client-max-body-size: "0"
name: {{ .Release.Name }}
spec:
rules:
- host: test.dnet
http:
paths:
- backend:
service:
name: {{ .Release.Name }}
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- test-dnet
secretName: test-dnet-cert
---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: test-dnet
spec:
secretName: test-dnet-cert
issuerRef:
name: vault-issuer
kind: ClusterIssuer
commonName: test.dnet
dnsNames:
- test.dnet
Kubernetes External Vault Auth
https://learn.hashicorp.com/tutorials/vault/kubernetes-external-vault?in=vault/kubernetes
Connect to external vault
# On the new server (pikube - vault)
helm install vault hashicorp/vault \
--set "injector.externalVaultAddr=https://vault.ducoterra.net"
VAULT_HELM_SECRET_NAME=$(kubectl get secrets --output=json | jq -r '.items[].metadata | select(.name|startswith("vault-token-")).name')
TOKEN_REVIEW_JWT=$(kubectl get secret $VAULT_HELM_SECRET_NAME --output='go-template={{ .data.token }}' | base64 --decode)
KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)
KUBE_HOST="https://3.14.3.104:6443"
# On the existing vault server
export PKI_PATH=dnet_inter
vault auth enable -path=pikube kubernetes
vault write auth/pikube/config \
token_reviewer_jwt="$TOKEN_REVIEW_JWT" \
kubernetes_host="https://3.14.3.104:6443" \
kubernetes_ca_cert="$KUBE_CA_CERT"
vault write auth/pikube/role/issuer \
bound_service_account_names=issuer \
bound_service_account_namespaces=cert-manager \
policies=$PKI_PATH \
ttl=20m
Install cert-manager
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.yaml
kubectl -n cert-manager create serviceaccount issuer
export ISSUER_SECRET_REF=$(kubectl -n cert-manager get serviceaccount issuer -o json | jq -r ".secrets[].name")
export PKI_PATH=dnet_inter
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: vault-issuer
spec:
vault:
server: https://vault.ducoterra.net
path: $PKI_PATH/sign/dnet
auth:
kubernetes:
mountPath: /v1/auth/pikube
role: issuer
secretRef:
name: $ISSUER_SECRET_REF
key: token
EOF
Auto-unseal
https://learn.hashicorp.com/tutorials/vault/autounseal-transit
Enable transit on vault that will do the unsealing
# Up the token ttl to 10 years (defaults to 32 days)
vault write sys/auth/token/tune max_lease_ttl=87600h
vault secrets enable transit
vault write -f transit/keys/autounseal
tee policies/autounseal.hcl <<EOF
path "transit/encrypt/autounseal" {
capabilities = [ "update" ]
}
path "transit/decrypt/autounseal" {
capabilities = [ "update" ]
}
EOF
vault policy write autounseal policies/autounseal.hcl
vault token create -policy="autounseal" -wrap-ttl=120 -ttl=87600h
VAULT_TOKEN="wrapping token" vault unwrap
Enable auto unseal with kube cluster
Create a test vault in a new namespace
kubectl apply -f k8s/certificate.yaml
# Get token from above output
kubectl create secret generic auto-unseal-token --from-literal=VAULT_TOKEN="token from output"
helm upgrade --install vault hashicorp/vault --values helm/ha.yaml
Test Auto Unseal
kubectl exec -it vault-0 -- vault operator init
kubectl exec -ti vault-1 -- vault operator raft join http://vault-0.vault-internal:8200
kubectl exec -ti vault-2 -- vault operator raft join http://vault-0.vault-internal:8200
SSH
Client key signing
Enable secrets engine and generate a key
vault secrets enable -path=ssh-client-signer ssh
vault write ssh-client-signer/config/ca generate_signing_key=true
To enable port-forwarding you'll need to update the parameters:
{
"permit-port-forwarding": ""
"permit-pty"
}
Retrieve the public CA (and add it to your /etc/ssh/trusted-user-ca-keys.pem) with
curl -o /etc/ssh/trusted-user-ca-keys.pem https://vault.ducoterra.net/v1/ssh-client-signer/public_key
Add it to your sshd_config
echo "TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem" >> /etc/ssh/sshd_config
Restart the SSH service
service ssh restart
Add signing role
vault write ssh-client-signer/roles/ducoterra -<<"EOH"
{
"allow_user_certificates": true,
"allowed_users": "ducoterra",
"allowed_extensions": "permit-pty,permit-port-forwarding",
"default_extensions": [
{ "permit-pty": "" }
],
"algorithm_signer": "rsa-sha2-512",
"key_type": "ca",
"default_user": "ducoterra",
"ttl": "30m0s"
}
EOH
vault write ssh-client-signer/roles/pi -<<"EOH"
{
"allow_user_certificates": true,
"allowed_users": "pi",
"allowed_extensions": "permit-pty,permit-port-forwarding",
"default_extensions": [
{ "permit-pty": "" }
],
"algorithm_signer": "rsa-sha2-512",
"key_type": "ca",
"default_user": "pi",
"ttl": "30m0s"
}
EOH
vault write ssh-client-signer/roles/rancher -<<"EOH"
{
"allow_user_certificates": true,
"allowed_users": "rancher",
"allowed_extensions": "permit-pty,permit-port-forwarding",
"default_extensions": [
{ "permit-pty": "" }
],
"algorithm_signer": "rsa-sha2-512",
"key_type": "ca",
"default_user": "rancher",
"ttl": "30m0s"
}
EOH
Sign a key
export SSHUSER=pi; vault write -field=signed_key ssh-client-signer/sign/$SSHUSER public_key=@$HOME/.ssh/id_rsa.pub > ~/.ssh/id_rsa-cert.pub
SSH using the signed key
# If you saved the signed pub as key_name"-cert.pub" then you don't need to specify the signed-cert.pub part.
ssh -i signed-cert.pub -i ~/.ssh/test_rsa client
# without the cert (using default client)
ssh -i ~/.ssh/test_rsa client
Server Host Signing
Enable secrets engine
vault secrets enable -path=ssh-host-signer ssh
Generate keys:
vault write ssh-host-signer/config/ca generate_signing_key=true
Extend host key's TTL
vault secrets tune -max-lease-ttl=87600h ssh-host-signer
Create host role
vault write ssh-host-signer/roles/hostrole \
key_type=ca \
ttl=87600h \
allow_host_certificates=true \
allowed_domains="localdomains,dnet,hole,ducoterra.net" \
allow_subdomains=true
Sign the host's public key
vault write ssh-host-signer/sign/hostrole \
cert_type=host \
public_key=@$HOME/.ssh/id_rsa.pub
Write the signed certificate to the ssh config on the host
vault write -field=signed_key ssh-host-signer/sign/hostrole \
cert_type=host \
public_key=@$HOME/.ssh/id_rsa.pub > /etc/ssh/ssh_host_rsa_key-cert.pub
Assign correct permissions
chmod 0640 /etc/ssh/ssh_host_rsa_key-cert.pub
Add to sshd_config
echo HostKey /etc/ssh/ssh_host_rsa_key >> /etc/ssh/sshd_config
echo HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub >> /etc/ssh/sshd_config
Restart the ssh service
service ssh restart
Add certificate to client
echo '@cert-authority *.ducoterra.net '$(vault read -field=public_key ssh-host-signer/config/ca) >> ~/.ssh/known_hosts
AWS
Credential Management
https://www.vaultproject.io/docs/secrets/aws
Enable AWS secrets
vault secrets enable aws
vault secrets tune -default-lease-ttl=24h aws
Allow user to access AWS path
path "aws/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
Create a vault-secret user
# Generate a vault-root-user
export VAULT_ROOT_USER_ARN=$(aws iam create-user --user-name vault-root-user | jq -r '.User.Arn')
# Create a root user policy template with the user arn
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
export VAULT_PUPPET_ARNS='arn:aws:iam::'$ACCOUNT_ID':user/vault-*'
jq -r ".Statement[].Resource[0] = \"$VAULT_PUPPET_ARNS\"" < aws/vault_root_policy.json > /tmp/vault_root_policy.json
# Create the vault root user policy from the template
export VAULT_ROOT_USER_POLICY_ARN=$(aws iam create-policy --policy-name vault-root-policy --policy-document file:///tmp/vault_root_policy.json | jq -r '.Policy.Arn')
# Attach the vault root user policy
aws iam attach-user-policy --user-name vault-root-user --policy-arn $VAULT_ROOT_USER_POLICY_ARN
# Create the key rotation policy
jq -r ".Statement[].Resource[0] = \"$VAULT_ROOT_USER_ARN\"" < aws/vault_root_rotate_policy.json > /tmp/vault_root_rotate_policy.json
export VAULT_ROOT_USER_ROTATE_POLICY_ARN=$(aws iam create-policy --policy-name vault-root-rotate-policy --policy-document file:///tmp/vault_root_rotate_policy.json | jq -r '.Policy.Arn')
# Attach the key rotation policy
aws iam attach-user-policy --user-name vault-root-user --policy-arn $VAULT_ROOT_USER_ROTATE_POLICY_ARN
# Create access keys for the vault-root-user
export $(aws iam create-access-key --user-name vault-root-user | jq -r '"VAULT_ROOT_ACCESS_KEY_ID=\(.AccessKey.AccessKeyId) VAULT_ROOT_SECRET_ACCESS_KEY=\(.AccessKey.SecretAccessKey)"')
Write aws root config with access key and secret key from above
vault write aws/config/root \
access_key=$VAULT_ROOT_ACCESS_KEY_ID \
secret_key=$VAULT_ROOT_SECRET_ACCESS_KEY \
region=us-east-2
Rotate your credentials
vault write -f aws/config/rotate-root
Creating IAM Users
Create a terraform-user role
vault write aws/roles/terraform-user \
credential_type=iam_user \
policy_document=@aws/terraform_policy.json
Read credentials
vault read aws/creds/terraform-user
Automate credentials generation (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)
export $(vault read -format json aws/creds/terraform-user | jq -r '"AWS_ACCESS_KEY_ID=\(.data.access_key) AWS_SECRET_ACCESS_KEY=\(.data.secret_key)"')
export AWS_DEFAULT_REGION=us-east-2
export AWS_PROFILE=default
aws configure set region $AWS_DEFAULT_REGION --profile default
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID --profile default
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY --profile default
STS Tokens
To create STS federated tokens use the following permissions:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": [
"sts:GetFederationToken"
],
"Resource": "*"
}
}
Create a role with the example policy
vault write aws/roles/ec2_admin \
credential_type=federation_token \
policy_document=@aws/ec2_admin.json
Generate a role with a ttl of 60 minutes
vault write aws/sts/ec2_admin ttl=24h
Authentication
Create a vault aws policy
vault policy write aws_wireguard policies/aws_wireguard.hcl
Create a vault-auth user
# Generate a vault-auth-user
export VAULT_AUTH_USER_ARN=$(aws iam create-user --user-name vault-auth-user | jq -r '.User.Arn')
# Create an auth user policy template with the user arn
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
# Create the vault auth user policy from the template
export VAULT_AUTH_USER_POLICY_ARN=$(aws iam create-policy --policy-name vault-auth-policy --policy-document file://aws/vault_auth_policy.json | jq -r '.Policy.Arn')
# Attach the vault root user policy
aws iam attach-user-policy --user-name vault-auth-user --policy-arn $VAULT_AUTH_USER_POLICY_ARN
# Generate credentials
export $(aws iam create-access-key --user-name vault-auth-user | jq -r '"VAULT_AUTH_ACCESS_KEY_ID=\(.AccessKey.AccessKeyId) VAULT_AUTH_SECRET_ACCESS_KEY=\(.AccessKey.SecretAccessKey)"')
# Write credentials to vault
vault write auth/aws/config/client secret_key=$VAULT_AUTH_SECRET_ACCESS_KEY access_key=$VAULT_AUTH_ACCESS_KEY_ID
Create a vault-auth role
# Create the role
exort VAULT_AUTH_ROLE_ARN=$(aws iam create-role --role-name vault-auth-role --assume-role-policy-document file://aws/vault_auth_trust_policy.json | jq -r '.Role.Arn')
Create the vault role with the role arn
vault write auth/aws/role/aws-wireguard auth_type=iam bound_iam_principal_arn=$VAULT_AUTH_ROLE_ARN policies=aws_wireguard max_ttl=30m
vault write auth/aws/config/client iam_server_id_header_value=vault.ducoterra.net
Login on the ec2 instance
vault login -method=aws header_value=vault.ducoterra.net role=aws-wireguard